diff --git a/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue b/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue new file mode 100644 index 000000000..73e24c199 --- /dev/null +++ b/apps/desktop/src/components/common/ElasticsearchJsonResponsePanel.vue @@ -0,0 +1,120 @@ + + + diff --git a/apps/desktop/src/components/common/JsonTree.vue b/apps/desktop/src/components/common/JsonTree.vue new file mode 100644 index 000000000..718a49057 --- /dev/null +++ b/apps/desktop/src/components/common/JsonTree.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/apps/desktop/src/components/layout/ContentArea.vue b/apps/desktop/src/components/layout/ContentArea.vue index 32a5fe7f6..42323f233 100644 --- a/apps/desktop/src/components/layout/ContentArea.vue +++ b/apps/desktop/src/components/layout/ContentArea.vue @@ -48,6 +48,7 @@ const DocumentBrowser = defineAsyncComponent(() => import("@/components/document const MongoGridFsBrowser = defineAsyncComponent(() => import("@/components/document/MongoGridFsBrowser.vue")); const MongoBucketBrowser = defineAsyncComponent(() => import("@/components/document/MongoBucketBrowser.vue")); const VectorBrowser = defineAsyncComponent(() => import("@/components/vector/VectorBrowser.vue")); +const ElasticsearchJsonResponsePanel = defineAsyncComponent(() => import("@/components/common/ElasticsearchJsonResponsePanel.vue")); const MqAdminConsole = defineAsyncComponent(() => import("@/components/mq/MqAdminConsole.vue")); const NacosAdminConsole = defineAsyncComponent(() => import("@/components/nacos/NacosAdminConsole.vue")); const ObjectBrowser = defineAsyncComponent(() => import("@/components/objects/ObjectBrowser.vue")); @@ -70,6 +71,7 @@ import { dataTabExecutionDatabase } from "@/lib/table/dataTabExecutionDatabase"; import { formatShortcut } from "@/lib/editor/shortcutRegistry"; import { effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect"; import { chartableColumnIndexes } from "@/lib/dataGrid/chartData"; +import { elasticsearchJsonResponseForResult } from "@/lib/elasticsearch/elasticsearchJsonResponse"; import * as api from "@/lib/backend/api"; import { applyMongoGridChangesToDocument, buildMongoUpdateDocument, formatMongoShellLiteral, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues"; import type { SqlExecutionOverride } from "@/lib/sql/sqlExecutionTarget"; @@ -321,6 +323,7 @@ const resultRuns = computed(() => resultRunItems(props.activeTab)); const activeResultRunItem = computed(() => resultRuns.value.find((run) => run.active)); const activeResultGridCacheKey = computed(() => resultGridCacheKey(props.activeTab)); const activeResultSql = computed(() => resultSqlForGrid(props.activeTab)); +const activeElasticsearchJsonResponse = computed(() => elasticsearchJsonResponseForResult(activeEffectiveDatabaseType.value, activeResultSql.value, props.activeTab.result)); 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); @@ -339,7 +342,7 @@ const hasTabularResult = computed(() => { }); const canShowResultOutput = computed(() => hasTabularResult.value || props.activeTab.isExecuting); const canShowExplainOutput = computed(() => !!props.activeTab.explainPlan || !!props.activeTab.explainError || !!props.activeTab.explainTableResult || !!props.activeTab.explainTableError || props.activeTab.isExplaining === true); -const showStandaloneResultToolbar = computed(() => props.activeOutputView !== "result" || !props.activeTab.result || !hasTabularResult.value); +const showStandaloneResultToolbar = computed(() => activeElasticsearchJsonResponse.value || props.activeOutputView !== "result" || !props.activeTab.result || !hasTabularResult.value); const standaloneResultToolbarCompact = computed(() => standaloneResultToolbarWidth.value > 0 && standaloneResultToolbarWidth.value < DATA_GRID_COMPACT_TOPBAR_WIDTH); let standaloneResultToolbarResizeObserver: ResizeObserver | undefined; @@ -672,6 +675,12 @@ function refreshData(): boolean { emit("reload"); return true; } + if (activeElasticsearchJsonResponse.value) { + // Match DataGrid's toolbar refresh intent so multi-result runs are + // refreshed as a group instead of replacing them with the active result. + emit("reload", activeResultSql.value, undefined, undefined, undefined, undefined, undefined, "refresh"); + return true; + } if (!dataGridRef.value) return false; void dataGridRef.value.onToolbarRefresh(); return true; @@ -723,7 +732,7 @@ function toggleResultAutoSave() { function handleModRTarget(target: Element): boolean { if (target.closest("[data-query-editor-root]")) return queryEditorRef.value?.openReplace() ?? false; if (target.closest("[data-cell-detail-editor-root]")) return dataGridRef.value?.openCellDetailSearch() ?? false; - if (target.closest("[data-grid-root]")) return refreshData(); + if (target.closest("[data-grid-root], [data-elasticsearch-json-response-root]")) return refreshData(); if (canReloadUnavailableDataTab(props.activeTab)) return refreshData(); return false; } @@ -860,7 +869,7 @@ defineExpose({ focusSearch, refreshData, handleModRTarget, requestQueryEditorExe
- +
- + - +
@@ -1075,8 +1091,9 @@ defineExpose({ focusSearch, refreshData, handleModRTarget, requestQueryEditorExe