From 2a3844f2c6375047563f2224239310d7f8df2f99 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 8 Jun 2026 14:13:47 +0800 Subject: [PATCH] feat(results): add execution summary view --- apps/desktop/src/App.vue | 2 +- .../src/components/layout/ContentArea.vue | 129 +++++++++++++++--- .../src/composables/useSqlExecution.ts | 5 +- apps/desktop/src/i18n/locales/en.ts | 14 ++ apps/desktop/src/i18n/locales/zh-CN.ts | 14 ++ apps/desktop/src/lib/tabPresentation.ts | 37 ++++- packages/app-tests/tabPresentation.test.ts | 53 ++++++- 7 files changed, 231 insertions(+), 23 deletions(-) diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index e99bd185af..68e96fa127 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -125,7 +125,7 @@ const contentAreaRef = ref | null>(null); const selectedSql = ref(""); const cursorPos = ref(0); const formatSqlRequestId = ref(0); -const activeOutputView = ref<"result" | "explain" | "chart">("result"); +const activeOutputView = ref<"result" | "summary" | "explain" | "chart">("result"); const newQueryContextSource = ref<"tab" | "sidebar">("tab"); const showSaveSqlDialog = ref(false); const saveSqlName = ref(""); diff --git a/apps/desktop/src/components/layout/ContentArea.vue b/apps/desktop/src/components/layout/ContentArea.vue index 6feffd8796..02df3c21d5 100644 --- a/apps/desktop/src/components/layout/ContentArea.vue +++ b/apps/desktop/src/components/layout/ContentArea.vue @@ -17,6 +17,7 @@ import { Inbox, RefreshCcw, Wrench, + ListChecks, } from "@lucide/vue"; import { Splitpanes, Pane } from "splitpanes"; import "splitpanes/dist/splitpanes.css"; @@ -54,7 +55,7 @@ const ExplainPlanViewer = defineAsyncComponent(() => import("@/components/explai const QueryChart = defineAsyncComponent(() => import("@/components/chart/QueryChart.vue")); import { useQueryStore } from "@/stores/queryStore"; import { canCancelQueryExecution, queryExecutionLabelKey } from "@/lib/queryExecutionState"; -import { databaseDisplayNameForTab } from "@/lib/tabPresentation"; +import { databaseDisplayNameForTab, executionSummaryItems, tabularResultItems } from "@/lib/tabPresentation"; import { isTableDataEditable } from "@/lib/tableEditing"; import { tableMetaForDataTab } from "@/lib/tableDataTabMeta"; import { formatShortcut } from "@/lib/shortcutRegistry"; @@ -90,14 +91,14 @@ const props = defineProps<{ activeTab: QueryTab; activeConnection?: ConnectionConfig; executableSql: string; - activeOutputView: "result" | "explain" | "chart"; + activeOutputView: "result" | "summary" | "explain" | "chart"; formatSqlRequestId: number; selectedSql: string; cursorPos: number; }>(); const emit = defineEmits<{ - "update:activeOutputView": [value: "result" | "explain" | "chart"]; + "update:activeOutputView": [value: "result" | "summary" | "explain" | "chart"]; fixWithAi: [errorMessage: string]; execute: [sqlOverride?: string]; saveSql: []; @@ -207,6 +208,13 @@ const hasQueryOutput = computed( props.activeTab.isExecuting === true || props.activeTab.isExplaining === true, ); +const tabularResults = computed(() => tabularResultItems(props.activeTab.results)); +const summaryItems = computed(() => executionSummaryItems(props.activeTab)); +const hasExecutionSummary = computed(() => summaryItems.value.length > 0 || props.activeTab.isExecuting); +const hasTabularResult = computed(() => { + if (props.activeTab.result?.columns.length) return true; + return tabularResults.value.length > 0; +}); const resultsPaneOpen = ref(false); watch( @@ -224,6 +232,17 @@ watch( }, ); +watch( + () => [props.activeTab.id, props.activeTab.result, props.activeTab.results, props.activeTab.isExecuting] as const, + () => { + if (props.activeTab.isExecuting) return; + if (hasExecutionSummary.value && !hasTabularResult.value && props.activeOutputView === "result") { + emit("update:activeOutputView", "summary"); + } + }, + { immediate: true }, +); + watch( () => [props.activeTab.isExecuting, props.activeTab.isExplaining], ([isExecuting, isExplaining]) => { @@ -433,33 +452,38 @@ defineExpose({ focusSearch, refreshData, handleModRTarget }); size="sm" :variant="activeOutputView === 'result' ? 'secondary' : 'ghost'" class="h-6 px-2 text-xs" - :disabled="!activeTab.result && !activeTab.isExecuting" + :disabled="!hasTabularResult && !activeTab.isExecuting" @click="emit('update:activeOutputView', 'result')" > {{ t("tabs.tableData") }} -