fix(meilisearch): show per-index size in the index sidebar
This commit is contained in:
14 files changed
+239
-18
No files matched your search
@@ -100,8 +100,17 @@ onMounted(() => {
|
||||
<div class="text-muted-foreground">{{ t("meilisearch.documentCountLabel") }}</div>
|
||||
<div class="mt-0.5 tabular-nums text-foreground/80">{{ overview ? overview.numberOfDocuments : "-" }}</div>
|
||||
</div>
|
||||
<div v-if="overview?.databaseSize != null">
|
||||
<div class="text-muted-foreground">{{ t("meilisearch.databaseSize") }}</div>
|
||||
<div v-if="overview?.documentSize != null">
|
||||
<div class="text-muted-foreground">{{ t("meilisearch.documentSize") }}</div>
|
||||
<div class="mt-0.5 tabular-nums text-foreground/80">{{ formatBytes(overview.documentSize) }}</div>
|
||||
</div>
|
||||
<div v-if="overview?.avgDocumentSize != null">
|
||||
<div class="text-muted-foreground">{{ t("meilisearch.avgDocumentSize") }}</div>
|
||||
<div class="mt-0.5 tabular-nums text-foreground/80">{{ formatBytes(overview.avgDocumentSize) }}</div>
|
||||
</div>
|
||||
<!-- Older servers report no per-index size; label the instance-wide number so it is not read as this index's size. -->
|
||||
<div v-else-if="overview?.databaseSize != null">
|
||||
<div class="text-muted-foreground">{{ t("meilisearch.instanceDatabaseSize") }}</div>
|
||||
<div class="mt-0.5 tabular-nums text-foreground/80">{{ formatBytes(overview.databaseSize) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { createApp, defineComponent, h, nextTick, ref, type Component } from "vue";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => ({ getIndexOverview: vi.fn() }));
|
||||
|
||||
function passthrough(tag: string): Component {
|
||||
return defineComponent({
|
||||
inheritAttrs: false,
|
||||
setup(_, { attrs, slots }) {
|
||||
return () => h(tag, attrs, slots.default?.());
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
vi.mock("vue-i18n", () => ({
|
||||
useI18n: () => ({ locale: ref("zh-CN"), t: (key: string) => key }),
|
||||
}));
|
||||
vi.mock("@lucide/vue", () => ({
|
||||
Copy: passthrough("span"),
|
||||
FileText: passthrough("span"),
|
||||
ListChecks: passthrough("span"),
|
||||
Settings: passthrough("span"),
|
||||
}));
|
||||
vi.mock("@/lib/backend/api", () => ({ meilisearchGetIndexOverview: mocks.getIndexOverview }));
|
||||
vi.mock("@/composables/useToast", () => ({ useToast: () => ({ toast: vi.fn() }) }));
|
||||
vi.mock("@/lib/tabs/tabUiState", () => ({ useTabUiState: () => ({ initialState: {}, track: () => {} }) }));
|
||||
vi.mock("@/components/meilisearch/MeilisearchDocumentsPage.vue", () => ({ default: passthrough("div") }));
|
||||
vi.mock("@/components/meilisearch/MeilisearchSettingsPage.vue", () => ({ default: passthrough("div") }));
|
||||
vi.mock("@/components/meilisearch/MeilisearchTasksPage.vue", () => ({ default: passthrough("div") }));
|
||||
|
||||
import MeilisearchIndexView from "@/components/meilisearch/MeilisearchIndexView.vue";
|
||||
|
||||
let app: ReturnType<typeof createApp> | undefined;
|
||||
let root: HTMLDivElement | undefined;
|
||||
|
||||
async function mountIndexView() {
|
||||
root = document.createElement("div");
|
||||
document.body.append(root);
|
||||
app = createApp(MeilisearchIndexView, { connectionId: "c1", index: "report_template" });
|
||||
app.mount(root);
|
||||
await vi.waitFor(() => expect(mocks.getIndexOverview).toHaveBeenCalledTimes(1));
|
||||
await nextTick();
|
||||
return root;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mocks.getIndexOverview.mockReset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
app?.unmount();
|
||||
root?.remove();
|
||||
app = undefined;
|
||||
root = undefined;
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("MeilisearchIndexView storage rows", () => {
|
||||
// Meilisearch >= 1.14 reports the index's own sizes, so the sidebar must show
|
||||
// them. Reporting the instance-wide `databaseSize` here made every index look
|
||||
// like it owned the whole instance (issue #9880).
|
||||
it("shows the index's own size instead of the instance-wide number", async () => {
|
||||
mocks.getIndexOverview.mockResolvedValue({
|
||||
uid: "report_template",
|
||||
primaryKey: "id",
|
||||
createdAt: "2026-09-21T06:30:00Z",
|
||||
updatedAt: "2026-09-21T06:30:46Z",
|
||||
numberOfDocuments: 256,
|
||||
isIndexing: false,
|
||||
documentSize: 309_329_920,
|
||||
avgDocumentSize: 1_208_320,
|
||||
databaseSize: 4_194_304_000,
|
||||
});
|
||||
|
||||
const mounted = await mountIndexView();
|
||||
const text = mounted.textContent ?? "";
|
||||
|
||||
expect(text).toContain("meilisearch.documentSize");
|
||||
expect(text).toContain("meilisearch.avgDocumentSize");
|
||||
expect(text).not.toContain("meilisearch.instanceDatabaseSize");
|
||||
expect(text).toContain("295.0 MB");
|
||||
expect(text).not.toContain("3.9 GB");
|
||||
});
|
||||
|
||||
it("labels the instance-wide size as such on servers without per-index sizes", async () => {
|
||||
mocks.getIndexOverview.mockResolvedValue({
|
||||
uid: "report_template",
|
||||
primaryKey: "id",
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
numberOfDocuments: 256,
|
||||
isIndexing: false,
|
||||
documentSize: null,
|
||||
avgDocumentSize: null,
|
||||
databaseSize: 26_935_296,
|
||||
});
|
||||
|
||||
const mounted = await mountIndexView();
|
||||
const text = mounted.textContent ?? "";
|
||||
|
||||
expect(text).toContain("meilisearch.instanceDatabaseSize");
|
||||
expect(text).not.toContain("meilisearch.documentSize");
|
||||
expect(text).toContain("25.7 MB");
|
||||
});
|
||||
});
|
||||
@@ -5610,6 +5610,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "Əsas açar",
|
||||
documentCountLabel: "Sənədlər",
|
||||
databaseSize: "Verilənlər bazasının ölçüsü",
|
||||
documentSize: "Sənəd ölçüsü",
|
||||
avgDocumentSize: "Orta sənəd ölçüsü",
|
||||
instanceDatabaseSize: "İnstansiya verilənlər bazasının ölçüsü",
|
||||
copyDocument: "JSON-u kopyala",
|
||||
copied: "Kopyalandı",
|
||||
autoRefresh: "Avtomatik yeniləmə",
|
||||
|
||||
@@ -6029,6 +6029,9 @@ export default {
|
||||
primaryKey: "Primary key",
|
||||
documentCountLabel: "Documents",
|
||||
databaseSize: "Database size",
|
||||
documentSize: "Document size",
|
||||
avgDocumentSize: "Average document size",
|
||||
instanceDatabaseSize: "Instance database size",
|
||||
copyDocument: "Copy JSON",
|
||||
copied: "Copied",
|
||||
autoRefresh: "Auto refresh",
|
||||
|
||||
@@ -5571,6 +5571,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "Clave primaria",
|
||||
documentCountLabel: "Documentos",
|
||||
databaseSize: "Tamaño de la base de datos",
|
||||
documentSize: "Tamaño del documento",
|
||||
avgDocumentSize: "Tamaño medio del documento",
|
||||
instanceDatabaseSize: "Tamaño de la base de datos de la instancia",
|
||||
copyDocument: "Copiar JSON",
|
||||
copied: "Copiado",
|
||||
autoRefresh: "Actualización automática",
|
||||
|
||||
@@ -5568,6 +5568,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "Chiave primaria",
|
||||
documentCountLabel: "Documenti",
|
||||
databaseSize: "Dimensione del database",
|
||||
documentSize: "Dimensione del documento",
|
||||
avgDocumentSize: "Dimensione media del documento",
|
||||
instanceDatabaseSize: "Dimensione del database dell'istanza",
|
||||
copyDocument: "Copia JSON",
|
||||
copied: "Copiato",
|
||||
autoRefresh: "Aggiornamento automatico",
|
||||
|
||||
@@ -5596,6 +5596,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "主キー",
|
||||
documentCountLabel: "ドキュメント数",
|
||||
databaseSize: "データベースサイズ",
|
||||
documentSize: "ドキュメントサイズ",
|
||||
avgDocumentSize: "平均ドキュメントサイズ",
|
||||
instanceDatabaseSize: "インスタンスのデータベースサイズ",
|
||||
copyDocument: "JSON をコピー",
|
||||
copied: "コピーしました",
|
||||
autoRefresh: "自動更新",
|
||||
|
||||
@@ -5215,6 +5215,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "기본 키",
|
||||
documentCountLabel: "문서 수",
|
||||
databaseSize: "데이터베이스 크기",
|
||||
documentSize: "문서 크기",
|
||||
avgDocumentSize: "평균 문서 크기",
|
||||
instanceDatabaseSize: "인스턴스 데이터베이스 크기",
|
||||
copyDocument: "JSON 복사",
|
||||
copied: "복사됨",
|
||||
autoRefresh: "자동 새로고침",
|
||||
|
||||
@@ -5570,6 +5570,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "Chave primária",
|
||||
documentCountLabel: "Documentos",
|
||||
databaseSize: "Tamanho do banco de dados",
|
||||
documentSize: "Tamanho do documento",
|
||||
avgDocumentSize: "Tamanho médio do documento",
|
||||
instanceDatabaseSize: "Tamanho do banco de dados da instância",
|
||||
copyDocument: "Copiar JSON",
|
||||
copied: "Copiado",
|
||||
autoRefresh: "Atualização automática",
|
||||
|
||||
@@ -5504,6 +5504,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "Birincil anahtar",
|
||||
documentCountLabel: "Belgeler",
|
||||
databaseSize: "Veritabanı boyutu",
|
||||
documentSize: "Belge boyutu",
|
||||
avgDocumentSize: "Ortalama belge boyutu",
|
||||
instanceDatabaseSize: "Örnek veritabanı boyutu",
|
||||
copyDocument: "JSON Kopyala",
|
||||
copied: "Kopyalandı",
|
||||
autoRefresh: "Otomatik yenile",
|
||||
|
||||
@@ -6002,6 +6002,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "主键",
|
||||
documentCountLabel: "文档数",
|
||||
databaseSize: "数据库大小",
|
||||
documentSize: "文档大小",
|
||||
avgDocumentSize: "平均文档大小",
|
||||
instanceDatabaseSize: "实例数据库大小",
|
||||
copyDocument: "复制 JSON",
|
||||
copied: "已复制",
|
||||
autoRefresh: "自动刷新",
|
||||
|
||||
@@ -4885,6 +4885,9 @@ export default withEnglishFallback({
|
||||
primaryKey: "主鍵",
|
||||
documentCountLabel: "文件數",
|
||||
databaseSize: "資料庫大小",
|
||||
documentSize: "文件大小",
|
||||
avgDocumentSize: "平均文件大小",
|
||||
instanceDatabaseSize: "實例資料庫大小",
|
||||
copyDocument: "複製 JSON",
|
||||
copied: "已複製",
|
||||
autoRefresh: "自動重新整理",
|
||||
|
||||
@@ -4739,6 +4739,11 @@ export interface MeilisearchIndexOverview {
|
||||
updatedAt: string | null;
|
||||
numberOfDocuments: number;
|
||||
isIndexing: boolean;
|
||||
/** Raw document store size of this index (Meilisearch >= 1.14); null on older servers. */
|
||||
documentSize: number | null;
|
||||
/** Average document size of this index (Meilisearch >= 1.14); null on older servers. */
|
||||
avgDocumentSize: number | null;
|
||||
/** Instance-wide database size; every index shares it, so it is only a fallback. */
|
||||
databaseSize: number | null;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user