diff --git a/apps/desktop/src/components/transfer/DataTransferDialog.vue b/apps/desktop/src/components/transfer/DataTransferDialog.vue index c0c61a6cbc..2ad02ddc27 100644 --- a/apps/desktop/src/components/transfer/DataTransferDialog.vue +++ b/apps/desktop/src/components/transfer/DataTransferDialog.vue @@ -27,7 +27,7 @@ import type { TransferTask, TransferTaskConfig } from "@/types/database"; import { isSchemaAware, supportsTransfer } from "@/lib/database/databaseCapabilities"; import { transferDatabaseTypeForConnection } from "@/lib/database/jdbcDialect"; import { isDorisFamilyCatalogCapable } from "@/lib/database/databaseFeatureSupport"; -import { decodeTransferDatabaseOption, encodeTransferDatabaseOptions, isSameTransferDatabase, isTransferDatabaseSelected, normalizeTransferCatalog } from "@/lib/database/dataTransferSelection"; +import { decodeTransferDatabaseOption, encodeTransferDatabaseOptions, formatTransferEndpointLabel, isSameTransferDatabase, isTransferDatabaseSelected, normalizeTransferCatalog } from "@/lib/database/dataTransferSelection"; import { formatDatabaseLabel } from "@/lib/database/defaultDatabase"; import { databaseOptionsForConnection, fetchCatalogNamespaceOptions, fetchNamespaceOptionsForConnection, namespaceOptionsAreSchemas } from "@/composables/useDatabaseOptions"; import { useExportTracker } from "@/composables/useExportTracker"; @@ -1046,8 +1046,8 @@ function transferStrategyLabel(request: api.TransferRequest): string { const confirmationSummary = computed(() => { const request = confirmationRequest.value; if (!request) return ""; - const source = `${getConnectionName(request.sourceConnectionId)}.${request.sourceDatabase}.${request.sourceSchema}`; - const target = `${getConnectionName(request.targetConnectionId)}.${request.targetDatabase}.${request.targetSchema}`; + const source = formatTransferEndpointLabel(getConnectionName(request.sourceConnectionId), request.sourceDatabase, request.sourceSchema, request.sourceCatalog); + const target = formatTransferEndpointLabel(getConnectionName(request.targetConnectionId), request.targetDatabase, request.targetSchema, request.targetCatalog); const count = request.tables.length + request.objects.reduce((total, selection) => total + selection.names.length, 0); return t("transfer.startConfirmMessage", { source, target, count }); }); diff --git a/apps/desktop/src/lib/__tests__/database/dataTransferSelection.spec.ts b/apps/desktop/src/lib/__tests__/database/dataTransferSelection.spec.ts index 2414c9e348..09c2445d62 100644 --- a/apps/desktop/src/lib/__tests__/database/dataTransferSelection.spec.ts +++ b/apps/desktop/src/lib/__tests__/database/dataTransferSelection.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { decodeTransferDatabaseOption, encodeTransferDatabaseOptions, isSameTransferDatabase, isTransferDatabaseSelected, normalizeTransferCatalog, type TransferDatabaseSelection } from "@/lib/database/dataTransferSelection"; +import { decodeTransferDatabaseOption, encodeTransferDatabaseOptions, formatTransferEndpointLabel, isSameTransferDatabase, isTransferDatabaseSelected, normalizeTransferCatalog, type TransferDatabaseSelection } from "@/lib/database/dataTransferSelection"; import { TREE_SCHEMA_DEFAULT_DATABASE_SELECT_VALUE } from "@/lib/database/defaultDatabase"; import type { CatalogInfo } from "@/types/database"; @@ -57,4 +57,16 @@ describe("data transfer database selection", () => { it("compares connection and database fields without concatenation collisions", () => { expect(isSameTransferDatabase(selection({ connectionId: "ab", database: "c" }), selection({ connectionId: "a", database: "bc" }))).toBe(false); }); + + it("omits schema when it repeats the database name", () => { + expect(formatTransferEndpointLabel("127.0.0.1", "russia_b2b_catalog", "russia_b2b_catalog")).toBe("127.0.0.1.russia_b2b_catalog"); + expect(formatTransferEndpointLabel("192.168.1.183", "russia_b2b_catalog", "russia_b2b_catalog")).toBe("192.168.1.183.russia_b2b_catalog"); + }); + + it("keeps a distinct schema and optional catalog in the confirmation label", () => { + expect(formatTransferEndpointLabel("warehouse", "app", "public")).toBe("warehouse.app.public"); + expect(formatTransferEndpointLabel("oracle", "", "HR")).toBe("oracle.HR"); + expect(formatTransferEndpointLabel("doris", "sales", "sales", "iceberg")).toBe("doris.iceberg.sales"); + expect(formatTransferEndpointLabel("prod", "app", "public", "hive")).toBe("prod.hive.app.public"); + }); }); diff --git a/apps/desktop/src/lib/database/dataTransferSelection.ts b/apps/desktop/src/lib/database/dataTransferSelection.ts index 2044149731..c15b87c421 100644 --- a/apps/desktop/src/lib/database/dataTransferSelection.ts +++ b/apps/desktop/src/lib/database/dataTransferSelection.ts @@ -31,3 +31,17 @@ export function normalizeTransferCatalog(catalog: string, catalogs: readonly Cat export function isSameTransferDatabase(source: TransferDatabaseSelection, target: TransferDatabaseSelection): boolean { return source.connectionId === target.connectionId && source.database === target.database && normalizeTransferCatalog(source.catalog, source.catalogs) === normalizeTransferCatalog(target.catalog, target.catalogs); } + +/** Confirmation label: skip schema when it equals the database name (MySQL). */ +export function formatTransferEndpointLabel(connectionName: string, database: string, schema: string, catalog?: string): string { + const parts: string[] = []; + const name = connectionName.trim(); + if (name) parts.push(name); + const catalogName = catalog?.trim() ?? ""; + if (catalogName) parts.push(catalogName); + const databaseName = database.trim(); + if (databaseName) parts.push(databaseName); + const schemaName = schema.trim(); + if (schemaName && schemaName !== databaseName) parts.push(schemaName); + return parts.join("."); +}