From a49137ae8b84026720c52840f6cf22caed2da7b7 Mon Sep 17 00:00:00 2001 From: weiyong <1044070878@qq.com> Date: Mon, 27 Jul 2026 18:55:37 +0800 Subject: [PATCH] feat(elasticsearch): add custom checks and tabular REST results --- apps/desktop/src/App.vue | 4 +- .../common/ElasticsearchJsonResponsePanel.vue | 9 + .../connection/ConnectionDialog.vue | 11 +- .../src/components/layout/ContentArea.vue | 26 ++ .../sidebar/SidebarTreeRuntimeHost.vue | 1 + .../__tests__/useDataGridExport.spec.ts | 33 +- .../src/composables/useDataGridExport.ts | 10 +- .../src/composables/useDataGridExtractor.ts | 13 +- apps/desktop/src/i18n/locales/en.ts | 2 + apps/desktop/src/i18n/locales/es.ts | 2 + apps/desktop/src/i18n/locales/it.ts | 2 + apps/desktop/src/i18n/locales/ja.ts | 2 + apps/desktop/src/i18n/locales/pt-BR.ts | 2 + apps/desktop/src/i18n/locales/zh-CN.ts | 2 + apps/desktop/src/i18n/locales/zh-TW.ts | 2 + .../connection/elasticsearchKibanaProxy.ts | 34 +- .../connectionStore.elasticsearchOpen.spec.ts | 139 ++++++ apps/desktop/src/stores/connectionStore.ts | 21 + apps/desktop/src/stores/queryStore.ts | 20 + apps/desktop/src/types/database.ts | 4 + crates/dbx-cli/src/main.rs | 1 + crates/dbx-core/src/data_grid_sql.rs | 20 + crates/dbx-core/src/db/clickhouse_driver.rs | 2 + crates/dbx-core/src/db/cloudflare_d1/mod.rs | 1 + .../dbx-core/src/db/elasticsearch_driver.rs | 431 +++++++++++++++--- crates/dbx-core/src/db/influxdb_driver.rs | 3 + crates/dbx-core/src/db/mysql.rs | 5 + crates/dbx-core/src/db/postgres.rs | 4 + crates/dbx-core/src/db/rqlite_driver.rs | 2 + crates/dbx-core/src/db/sqlite.rs | 2 + crates/dbx-core/src/db/sqlserver.rs | 10 + crates/dbx-core/src/db/turso_driver.rs | 4 + crates/dbx-core/src/db/vector_driver.rs | 2 + crates/dbx-core/src/query.rs | 21 + crates/dbx-core/src/schema.rs | 7 + crates/dbx-core/src/schema/kingbase.rs | 1 + crates/dbx-core/src/table_export.rs | 1 + .../src/table_structure_sql/sqlite_rebuild.rs | 1 + crates/dbx-core/src/transfer.rs | 3 + crates/dbx-core/src/types.rs | 5 + crates/dbx-mcp/src/backend.rs | 1 + packages/app-tests/dataGridSort.test.ts | 5 + .../elasticsearchKibanaProxy.test.ts | 20 + packages/app-tests/queryStore.test.ts | 102 +++++ 44 files changed, 918 insertions(+), 75 deletions(-) create mode 100644 apps/desktop/src/stores/__tests__/connectionStore.elasticsearchOpen.spec.ts diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 11e6db8ad..e3a1fa5ee 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -1691,7 +1691,7 @@ async function handleQuickOpenSelect(item: any) { } else if (config?.db_type === "mongodb") { await connectionStore.loadMongoDatabases(item.connectionId); } else if (config?.db_type === "elasticsearch") { - await connectionStore.loadElasticsearchIndices(item.connectionId); + await connectionStore.openElasticsearchConnectionTree(item.connectionId); } else if (config?.db_type === "qdrant" || config?.db_type === "milvus" || config?.db_type === "weaviate" || config?.db_type === "chromadb") { await connectionStore.loadVectorCollections(item.connectionId); } else if (config?.db_type === "mq") { @@ -1716,7 +1716,7 @@ async function handleQuickOpenSelect(item: any) { } else if (config?.db_type === "mongodb") { await connectionStore.loadMongoDatabases(item.connectionId); } else if (config?.db_type === "elasticsearch") { - await connectionStore.loadElasticsearchIndices(item.connectionId); + await connectionStore.openElasticsearchConnectionTree(item.connectionId); } else if (config?.db_type === "qdrant" || config?.db_type === "milvus" || config?.db_type === "weaviate" || config?.db_type === "chromadb") { await connectionStore.loadVectorCollections(item.connectionId); } else if (config?.db_type === "mq") { diff --git a/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue b/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue index 4e54f73af..457866561 100644 --- a/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue +++ b/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue @@ -13,6 +13,12 @@ import JsonTree from "./JsonTree.vue"; const props = defineProps<{ status: number; body: string; + /** When true, render a "Table" button to switch back to the grid view. */ + canShowTable?: boolean; +}>(); + +const emit = defineEmits<{ + showTable: []; }>(); const { t } = useI18n(); @@ -101,6 +107,9 @@ onMounted(() => { > {{ t("redis.jsonView") }} + diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index 23231b3ca..2379dd4ad 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -96,7 +96,7 @@ import { oceanbaseModeConnectionPatch, oceanbaseSubModeFromConfig } from "@/lib/ import { translateBackendError } from "@/i18n/backend-errors"; import { applyHiveKerberosSubmitConfig, hiveKerberosFormConfig, type HiveKerberosAuthMode } from "@/lib/database/hiveKerberosOptions"; import { hasCloudflareD1Credentials, isCloudflareD1Connection, normalizeCloudflareD1Connection } from "@/lib/connection/cloudflareD1"; -import { buildElasticsearchExternalConfig, elasticsearchConnectionModeFromConfig, elasticsearchKibanaBasePathFromConfig, type ElasticsearchConnectionMode } from "@/lib/connection/elasticsearchKibanaProxy"; +import { buildElasticsearchExternalConfig, elasticsearchConnectionModeFromConfig, elasticsearchConnectivityCheckPathFromConfig, elasticsearchKibanaBasePathFromConfig, type ElasticsearchConnectionMode } from "@/lib/connection/elasticsearchKibanaProxy"; type DbOption = { value: string; label: string }; type DbCategoryKey = "sql" | "analytics" | "domestic" | "lightweight" | "document" | "graph_ai" | "timeseries" | "mq" | "registry_config"; @@ -261,6 +261,7 @@ const defaultForm = (): ConnectionForm => ({ const elasticsearchConnectionMode = ref("direct"); const elasticsearchKibanaBasePath = ref(""); +const elasticsearchConnectivityCheckPath = ref(""); const elasticsearchConnectionPorts = ref>({ direct: 9200, kibana: 5601, @@ -270,6 +271,7 @@ function resetElasticsearchProxyFields(externalConfig?: unknown) { const mode = elasticsearchConnectionModeFromConfig(externalConfig); elasticsearchConnectionMode.value = mode; elasticsearchKibanaBasePath.value = elasticsearchKibanaBasePathFromConfig(externalConfig); + elasticsearchConnectivityCheckPath.value = elasticsearchConnectivityCheckPathFromConfig(externalConfig); elasticsearchConnectionPorts.value = { direct: mode === "direct" ? form.value.port : 9200, kibana: mode === "kibana" ? form.value.port : 5601, @@ -3191,7 +3193,7 @@ function connectionConfigForSubmit(id: string, generatedName = ""): ConnectionCo config.database = config.database?.trim() || undefined; } } else if (config.db_type === "elasticsearch") { - config.external_config = buildElasticsearchExternalConfig(elasticsearchConnectionMode.value, elasticsearchKibanaBasePath.value); + config.external_config = buildElasticsearchExternalConfig(elasticsearchConnectionMode.value, elasticsearchKibanaBasePath.value, elasticsearchConnectivityCheckPath.value); } else if (config.db_type === "sqlserver") { config.external_config = sqlServerPortExplicitFromConfig(config) ? { portExplicit: true } : undefined; } else { @@ -5874,6 +5876,11 @@ function openExternalUrl(url: string) { +
+ + +
+
diff --git a/apps/desktop/src/components/layout/ContentArea.vue b/apps/desktop/src/components/layout/ContentArea.vue index 409d30741..5d624e394 100644 --- a/apps/desktop/src/components/layout/ContentArea.vue +++ b/apps/desktop/src/components/layout/ContentArea.vue @@ -368,6 +368,19 @@ const activeStatementExecutionMarkers = computed(() => ), ); const activeElasticsearchJsonResponse = computed(() => elasticsearchJsonResponseForResult(activeEffectiveDatabaseType.value, activeResultSql.value, props.activeTab.result)); +/** Whether the active result is an Elasticsearch _source table that also has a raw JSON toggle. */ +const activeElasticsearchRawBody = computed(() => { + if (activeEffectiveDatabaseType.value !== "elasticsearch") return undefined; + return props.activeTab.result?.elasticsearch_raw_body; +}); +/** Toggle between the _source table and the raw JSON panel for Elasticsearch REST results. */ +const showElasticsearchRawJson = ref(false); +watch( + () => props.activeTab.result?.elasticsearch_raw_body, + () => { + showElasticsearchRawJson.value = false; + }, +); const resultArchiveExporting = ref(false); const canExportResultArchive = computed(() => props.activeTab.mode === "query" && (!!props.activeTab.result || !!props.activeTab.results?.length || !!props.activeTab.resultRuns?.length)); const resultAutoSave = computed(() => props.activeTab.resultAutoSave === true); @@ -1301,6 +1314,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand