feat(export): include query SQL in XLSX

This commit is contained in:
zipg authored and GitHub committed 2026-07-14 10:45:21 +08:00
1 parent 65ea4f855f
commit 73f11f4265
23 files changed
+486 -91

No files matched your search

+27 -3
View File
@@ -295,10 +295,11 @@ interface DataGridProps {
totalRowCountLoading?: boolean;
loading?: boolean;
cacheKey?: string;
exportSql?: string;
onExecuteSql?: (sql: string) => Promise<void>;
fullExportResult?: (onProgress?: (info: { rowsExported: number; totalRows: number | null }) => void) => Promise<QueryResult | undefined>;
queryResultExportRequest?: (options: { exportId: string; filePath: string; format: "csv" | "xlsx" | "txt" }) => Promise<api.QueryResultExportRequest | undefined>;
allExportResults?: Array<{ sheetName: string; result: QueryResult }>;
queryResultExportRequest?: (options: { exportId: string; filePath: string; format: "csv" | "xlsx" | "txt"; includeSqlSheet?: boolean }) => Promise<api.QueryResultExportRequest | undefined>;
allExportResults?: Array<{ sheetName: string; result: QueryResult; sql?: string }>;
exportFileBaseName?: string;
customSaveHandler?: import("@/composables/useDataGridEditor").CustomSaveHandler;
queryEditabilityReason?: QueryEditabilityReason;
@@ -4855,6 +4856,12 @@ function exportSelectedRowsXlsx() {
return exportXlsx(rowIds);
}
function exportSelectedRowsXlsxWithSql() {
const rowIds = affectedRowIds();
if (rowIds.length === 0) return;
return exportXlsxWithSql(rowIds);
}
function exportSelectedRowsJson() {
const rowIds = affectedRowIds();
if (rowIds.length === 0) return;
@@ -6553,8 +6560,11 @@ const {
exportMarkdown,
exportCurrentPageMarkdown,
exportXlsx,
exportXlsxWithSql,
exportCurrentPageXlsx,
exportCurrentPageXlsxWithSql,
exportAllResultsXlsx,
exportAllResultsXlsxWithSql,
exportSql,
exportCurrentPageSql,
exportTxt,
@@ -6564,6 +6574,7 @@ const {
columns: visibleColumns,
displayItems: visibleDisplayItems,
sql: computed(() => props.sql),
exportSql: computed(() => props.exportSql),
tableMeta: computed(() => (props.tableMeta ? { ...props.tableMeta } : undefined)),
copyInsertTargetLabel: computed(() => props.tableMeta?.tableName ?? props.customSaveHandler?.targetLabel),
databaseType: computed(() => props.databaseType),
@@ -6606,11 +6617,13 @@ const pageSizeMenuItems = computed(() =>
const exportMenuItems = computed(() => {
const hasFullResultExport = !!props.fullExportResult;
const allResultItems = (props.allExportResults?.length ?? 0) > 1 ? [{ value: "all-results-xlsx", label: t("grid.exportAllResultsXlsx"), separatorBefore: true }] : [];
const canIncludeSql = props.context === "results" && !!(props.exportSql || props.sql)?.trim();
const allResultItems = (props.allExportResults?.length ?? 0) > 1 ? [{ value: "all-results-xlsx", label: t("grid.exportAllResultsXlsx"), separatorBefore: true }, ...(canIncludeSql ? [{ value: "all-results-xlsx-with-sql", label: t("grid.exportAllResultsXlsxWithSql") }] : [])] : [];
const selectedItems = isMultiRow.value
? [
{ value: "selected-csv", label: t("grid.exportSelectedRowsCsv"), separatorBefore: true },
{ value: "selected-xlsx", label: t("grid.exportSelectedRowsXlsx") },
...(canIncludeSql ? [{ value: "selected-xlsx-with-sql", label: t("grid.exportSelectedRowsXlsxWithSql") }] : []),
{ value: "selected-json", label: t("grid.exportSelectedRowsJson") },
{ value: "selected-markdown", label: t("grid.exportSelectedRowsMarkdown") },
{ value: "selected-sql", label: t("grid.exportSelectedRowsSql") },
@@ -6622,6 +6635,7 @@ const exportMenuItems = computed(() => {
return [
{ value: "csv", label: t("grid.exportCsv") },
{ value: "xlsx", label: t("grid.exportXlsx") },
...(canIncludeSql ? [{ value: "xlsx-with-sql", label: t("grid.exportXlsxWithSql") }] : []),
{ value: "json", label: t("grid.exportJson") },
{ value: "markdown", label: t("grid.exportMarkdown") },
{ value: "sql", label: t("grid.exportSql") },
@@ -6634,12 +6648,14 @@ const exportMenuItems = computed(() => {
return [
{ value: "page-csv", label: t("grid.exportCurrentPageCsv") },
{ value: "page-xlsx", label: t("grid.exportCurrentPageXlsx") },
...(canIncludeSql ? [{ value: "page-xlsx-with-sql", label: t("grid.exportCurrentPageXlsxWithSql") }] : []),
{ value: "page-json", label: t("grid.exportCurrentPageJson") },
{ value: "page-markdown", label: t("grid.exportCurrentPageMarkdown") },
{ value: "page-sql", label: t("grid.exportCurrentPageSql") },
{ value: "page-txt", label: t("grid.exportCurrentPageTxt") },
{ value: "csv", label: t("grid.exportCurrentResultCsv"), separatorBefore: true },
{ value: "xlsx", label: t("grid.exportCurrentResultXlsx") },
...(canIncludeSql ? [{ value: "xlsx-with-sql", label: t("grid.exportCurrentResultXlsxWithSql") }] : []),
{ value: "json", label: t("grid.exportCurrentResultJson") },
{ value: "markdown", label: t("grid.exportCurrentResultMarkdown") },
{ value: "sql", label: t("grid.exportCurrentResultSql") },
@@ -6657,19 +6673,23 @@ function selectExportMenuItem(value: string) {
const actions: Record<string, () => void> = {
"page-csv": exportCurrentPageCsv,
"page-xlsx": exportCurrentPageXlsx,
"page-xlsx-with-sql": exportCurrentPageXlsxWithSql,
"page-json": exportCurrentPageJson,
"page-markdown": exportCurrentPageMarkdown,
"page-sql": exportCurrentPageSql,
"page-txt": exportCurrentPageTxt,
csv: exportCsv,
xlsx: exportXlsx,
"xlsx-with-sql": exportXlsxWithSql,
"all-results-xlsx": exportAllResultsXlsx,
"all-results-xlsx-with-sql": exportAllResultsXlsxWithSql,
json: exportJson,
markdown: exportMarkdown,
sql: exportSql,
txt: exportTxt,
"selected-csv": exportSelectedRowsCsv,
"selected-xlsx": exportSelectedRowsXlsx,
"selected-xlsx-with-sql": exportSelectedRowsXlsxWithSql,
"selected-json": exportSelectedRowsJson,
"selected-markdown": exportSelectedRowsMarkdown,
"selected-sql": exportSelectedRowsSql,
@@ -8813,11 +8833,15 @@ function exportSubmenu(): ContextMenuItem {
{ label: t("grid.exportSql"), action: exportSql },
{ label: t("grid.exportTxt"), action: exportTxt },
];
if (props.context === "results" && !!(props.exportSql || props.sql)?.trim()) {
items.splice(2, 0, { label: t("grid.exportXlsxWithSql"), action: exportXlsxWithSql });
}
if (isMultiRow.value) {
items.push(
{ label: "", separator: true },
{ label: t("grid.exportSelectedRowsCsv"), action: exportSelectedRowsCsv },
{ label: t("grid.exportSelectedRowsXlsx"), action: exportSelectedRowsXlsx },
...(props.context === "results" && !!(props.exportSql || props.sql)?.trim() ? [{ label: t("grid.exportSelectedRowsXlsxWithSql"), action: exportSelectedRowsXlsxWithSql }] : []),
{ label: t("grid.exportSelectedRowsJson"), action: exportSelectedRowsJson },
{ label: t("grid.exportSelectedRowsMarkdown"), action: exportSelectedRowsMarkdown },
{ label: t("grid.exportSelectedRowsSql"), action: exportSelectedRowsSql },
@@ -64,7 +64,7 @@ import { useConnectionStore } from "@/stores/connectionStore";
import { TABLE_FONT_SIZE_MAX, TABLE_FONT_SIZE_MIN, useSettingsStore, type DataGridSearchMode } from "@/stores/settingsStore";
import { useToast } from "@/composables/useToast";
import { canCancelQueryExecution, queryExecutionLabelKey } from "@/lib/sql/queryExecutionState";
import { databaseDisplayNameForTab, executionSummaryItems, resultGridCacheKey, resultRunItems, resultSourceRange, resultSqlForGrid, tabularResultItems } from "@/lib/tabs/tabPresentation";
import { databaseDisplayNameForTab, executionSummaryItems, queryResultExecutionSql, resultGridCacheKey, resultRunItems, resultSourceRange, resultSqlForGrid, tabularResultItems } from "@/lib/tabs/tabPresentation";
import { defaultQueryResultArchiveFileName } from "@/lib/query/queryResultArchive";
import { saveQueryResultArchiveFile } from "@/lib/query/queryResultArchiveFile";
import { isTableDataEditable } from "@/lib/table/tableEditing";
@@ -320,12 +320,14 @@ const allResultExportSheets = computed(() =>
tabularResults.value.map((item) => ({
sheetName: item.label || t("tabs.resultN", { n: item.n }),
result: item.result,
sql: item.index === props.activeTab.activeResultIndex ? queryResultExecutionSql(props.activeTab) : item.result.sourceStatement,
})),
);
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 activeResultExportSql = computed(() => queryResultExecutionSql(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));
@@ -1112,6 +1114,7 @@ defineExpose({ focusSearch, refreshData, handleModRTarget, requestQueryEditorExe
:sort-mode="activeTab.resultSortMode"
:initial-order-by-input="activeTab.orderByInput"
:sql="activeResultSql"
:export-sql="activeResultExportSql"
:loading="activeTab.isExecuting"
:editable="!!activeTab.queryAnalysis || !!mongoQueryResultSaveHandler"
:source-columns="activeTab.querySourceColumns"
@@ -1133,7 +1136,7 @@ defineExpose({ focusSearch, refreshData, handleModRTarget, requestQueryEditorExe
:total-row-count-loading="activeTab.resultTotalRowCountLoading"
:on-execute-sql="async (sql: string) => emit('executeSql', sql)"
:full-export-result="(onProgress?: (info: { rowsExported: number; totalRows: number | null }) => void) => queryStore.fetchTabResultForExport(activeTab.id, onProgress)"
:query-result-export-request="(options: { exportId: string; filePath: string; format: 'csv' | 'xlsx' | 'txt' }) => queryStore.buildQueryResultExportRequest(activeTab.id, options)"
:query-result-export-request="(options: { exportId: string; filePath: string; format: 'csv' | 'xlsx' | 'txt'; includeSqlSheet?: boolean }) => queryStore.buildQueryResultExportRequest(activeTab.id, options)"
:all-export-results="allResultExportSheets"
:export-file-base-name="activeTab.title"
@update:order-by-input="(v: string) => (activeTab.orderByInput = v)"