fix(export): name query result exports after result tab

This commit is contained in:
zipg
2026-09-22 01:09:48 +08:00
committed by GitHub
parent f28942421f
commit 529267cded
5 changed files with 46 additions and 1 deletions
@@ -171,6 +171,7 @@ import { elasticsearchJsonResponseForResult } from "@/lib/elasticsearch/elastics
import { elasticsearchProfileBodyForResult, parseElasticsearchProfile } from "@/lib/elasticsearch/elasticsearchProfile";
import * as api from "@/lib/backend/api";
import type { SqlInsertMode } from "@/lib/export/sqlInsertMode";
import { queryResultExportBaseName } from "@/lib/export/saveTextFile";
import { applyMongoGridChangesToDocument, applyMongoGridChangesToDocumentBaseline, buildMongoUpdateDocument, formatMongoShellLiteral, serializeMongoDocumentId, type MongoInputValue } from "@/lib/mongo/mongoDocumentValues";
import type { DataGridSortMode } from "@/lib/dataGrid/dataGridSort";
import { isDataGridToolbarCompact, type DataGridReloadIntent } from "@/lib/dataGrid/dataGridToolbar";
@@ -421,6 +422,10 @@ function increaseTableFontSize() {
setTableFontSize(tableFontSize.value + 1);
}
/** Export file base name for the query result grid: the result's label (nearby
* comment or `schema.table`) names exports, matching the result tab (#9894). */
const activeQueryResultExportBaseName = computed(() => queryResultExportBaseName(props.activeTab.result?.sourceLabel, props.activeTab.title));
const activeTabDimension = computed(() => {
const tab = props.activeTab;
if (!tab.connectionId || tab.mode !== "vector") return undefined;
@@ -2159,7 +2164,7 @@ defineExpose({
}) => queryStore.buildQueryResultExportRequest(activeTab.id, options)
"
:all-export-results="allResultExportSheets"
:export-file-base-name="activeTab.title"
:export-file-base-name="activeQueryResultExportBaseName"
@update:order-by-input="(v: string) => (activeTab.orderByInput = v)"
@local-column-filters-change="(filters: Record<string, string[]>) => queryStore.updateDataGridLocalColumnFilters(activeTab.id, filters)"
@reload="(sql?: string, searchText?: string, whereInput?: string, orderBy?: string, limit?: number, offset?: number, intent?: DataGridReloadIntent) => emit('reload', activeTab.id, sql, searchText, whereInput, orderBy, limit, offset, intent)"
@@ -0,0 +1,27 @@
import { describe, expect, it } from "vitest";
import { queryResultExportBaseName, sanitizeExportBaseName } from "@/lib/export/saveTextFile";
describe("queryResultExportBaseName", () => {
it("prefers the result label derived from the SQL's nearby comment", () => {
expect(queryResultExportBaseName("检查结果", "query 5")).toBe("检查结果");
});
it("falls back to the tab title when the result carries no label", () => {
expect(queryResultExportBaseName(undefined, "query 5")).toBe("query 5");
expect(queryResultExportBaseName("", "query 5")).toBe("query 5");
expect(queryResultExportBaseName(" ", "query 5")).toBe("query 5");
});
it("keeps the schema-qualified label so exported files stay identifiable", () => {
expect(queryResultExportBaseName("dbx.orders", "本地MySQL8.4@dbx")).toBe("dbx.orders");
});
it("returns undefined when neither source provides a name", () => {
expect(queryResultExportBaseName(undefined, undefined)).toBeUndefined();
expect(queryResultExportBaseName("", "")).toBeUndefined();
});
it("keeps the sanitized base name free of path separators", () => {
expect(sanitizeExportBaseName(queryResultExportBaseName("检查结果/2026", "query 5")!)).toBe("检查结果_2026");
});
});
@@ -39,6 +39,19 @@ export async function saveTextFile(content: string, defaultFileName: string, fil
return true;
}
/**
* Export file base name for a query result (#9894).
*
* The result tab is already named after the SQL's nearby comment (`-- name: x`
* or a plain leading comment) or after the `schema.table` that produced it, so
* an export of that result should reuse the same name instead of the generic
* query tab title ("query 3", "查询 3"). Table data tabs keep passing their
* table name, which is why the caller decides the fallback.
*/
export function queryResultExportBaseName(resultLabel: string | undefined, tabTitle: string | undefined): string | undefined {
return resultLabel?.trim() || tabTitle?.trim() || undefined;
}
export function sanitizeExportBaseName(value: string): string {
return replaceControlCharacters(
value
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB