feat(transfer): swap source and target connections

This commit is contained in:
GIWTO authored and GitHub committed 2026-08-26 21:38:10 +08:00
1 parent bf09181ba5
commit 96d2f0dd1c
9 files changed
+94 -2

No files matched your search

@@ -651,6 +651,88 @@ function resetState(cancelTaskLoad = true) {
savedConfigSnapshot.value = "";
}
/**
* 交换源和目标两侧:连接、Catalog、数据库、Schema 的选择随各自一侧整体互换,
* 一次点击即可反转传输方向。对象树只属于源端,旧选择作废,按新源端重新加载。
*/
function swapSourceAndTarget() {
const sourceState = {
connectionId: sourceConnectionId.value,
catalog: sourceCatalog.value,
catalogs: sourceCatalogs.value,
database: sourceDatabase.value,
databases: sourceDatabases.value,
schema: sourceSchema.value,
schemas: sourceSchemas.value,
};
const targetState = {
connectionId: targetConnectionId.value,
catalog: targetCatalog.value,
catalogs: targetCatalogs.value,
database: targetDatabase.value,
databases: targetDatabases.value,
schema: targetSchema.value,
schemas: targetSchemas.value,
};
if (sourceState.connectionId === targetState.connectionId && sourceState.catalog === targetState.catalog && sourceState.database === targetState.database && sourceState.schema === targetState.schema) {
// 两侧选择完全相同(含都未选择)时交换没有意义
return;
}
// 若正在加载已保存任务,先取消,避免任务加载链覆盖交换后的状态
taskLoadTracker.cancel();
pendingSourceSchemaPrefill.value = "";
pendingTargetSchemaPrefill.value = "";
pendingSelectedTablesPrefill.value = null;
pendingSelectedObjectsPrefill.value = null;
// 只在值确实变化时设置一次性跳过标记:标记由对应 watcher 消费,
// 若值未变则 watcher 不会触发,残留标记会误吞后续一次真实变更。
if (sourceConnectionId.value !== targetState.connectionId) {
skipSourceWatch.value = true;
sourceConnectionId.value = targetState.connectionId;
}
if (sourceCatalog.value !== targetState.catalog) {
skipSourceCatalogWatch.value = true;
sourceCatalog.value = targetState.catalog;
}
sourceCatalogs.value = targetState.catalogs;
if (sourceDatabase.value !== targetState.database) {
skipSourceDatabaseWatch.value = true;
sourceDatabase.value = targetState.database;
}
sourceDatabases.value = targetState.databases;
if (sourceSchema.value !== targetState.schema) {
skipSourceSchemaWatch.value = true;
sourceSchema.value = targetState.schema;
}
sourceSchemas.value = targetState.schemas;
if (targetConnectionId.value !== sourceState.connectionId) {
skipTargetWatch.value = true;
targetConnectionId.value = sourceState.connectionId;
}
if (targetCatalog.value !== sourceState.catalog) {
skipTargetCatalogWatch.value = true;
targetCatalog.value = sourceState.catalog;
}
targetCatalogs.value = sourceState.catalogs;
if (targetDatabase.value !== sourceState.database) {
skipTargetDatabaseWatch.value = true;
targetDatabase.value = sourceState.database;
}
targetDatabases.value = sourceState.databases;
targetSchema.value = sourceState.schema;
targetSchemas.value = sourceState.schemas;
// 对象树始终跟随源端:新源端是旧目标端,旧选择已无意义,清空后重新加载
objectGroups.value = {};
selectedObjects.value = {};
objectSearch.value = "";
void loadObjects();
}
async function startTransfer() {
if (!canStart.value || isSubmitting.value) return;
isSubmitting.value = true;
@@ -1037,9 +1119,11 @@ async function saveConfigTask() {
</div>
</div>
<!-- Arrow -->
<!-- Swap source / target -->
<div class="flex items-center pt-8">
<ArrowLeftRight class="w-5 h-5 text-muted-foreground" />
<Button variant="ghost" size="icon" class="h-7 w-7" :title="t('transfer.swap')" :aria-label="t('transfer.swap')" @click="swapSourceAndTarget">
<ArrowLeftRight class="w-3.5 h-3.5" />
</Button>
</div>
<!-- Target Section -->
+1
View File
@@ -5219,6 +5219,7 @@ export default {
searchCatalog: "Search catalog...",
sourceDatabase: "Source Database",
sourceSchema: "Source Schema",
swap: "Swap source and target",
targetConnection: "Target Connection",
targetDatabase: "Target Database",
targetSchema: "Target Schema",
+1
View File
@@ -5014,6 +5014,7 @@ export default withEnglishFallback({
overallProgress: "Progreso general",
dataTransfer: "Transferencia de datos",
sourceSchema: "Esquema de origen",
swap: "Intercambiar origen y destino",
targetSchema: "Esquema de destino",
runInBackground: "Ejecutar en segundo plano",
newTask: "Nueva transferencia",
+1
View File
@@ -4977,6 +4977,7 @@ export default withEnglishFallback({
sourceConnection: "Connessione Sorgente",
sourceDatabase: "Database Sorgente",
sourceSchema: "Schema Sorgente",
swap: "Inverti sorgente e destinazione",
targetConnection: "Connessione Destinazione",
targetDatabase: "Database Destinazione",
targetSchema: "Schema Destinazione",
+1
View File
@@ -5006,6 +5006,7 @@ export default withEnglishFallback({
sourceConnection: "ソース接続",
sourceDatabase: "ソースデータベース",
sourceSchema: "ソーススキーマ",
swap: "ソースとターゲットを入れ替え",
targetConnection: "ターゲット接続",
targetDatabase: "ターゲットデータベース",
targetSchema: "ターゲットスキーマ",
+1
View File
@@ -4644,6 +4644,7 @@ export default withEnglishFallback({
sourceConnection: "소스 연결",
sourceDatabase: "소스 데이터베이스",
sourceSchema: "소스 스키마",
swap: "소스와 대상 교체",
targetConnection: "대상 연결",
targetDatabase: "대상 데이터베이스",
targetSchema: "대상 스키마",
+1
View File
@@ -4979,6 +4979,7 @@ export default withEnglishFallback({
sourceConnection: "Conexão de origem",
sourceDatabase: "Banco de dados de origem",
sourceSchema: "Schema de origem",
swap: "Trocar origem e destino",
targetConnection: "Conexão de destino",
targetDatabase: "Banco de dados de destino",
targetSchema: "Schema de destino",
+1
View File
@@ -5204,6 +5204,7 @@ export default withEnglishFallback({
searchCatalog: "搜索 Catalog...",
sourceDatabase: "源数据库",
sourceSchema: "源 Schema",
swap: "交换源和目标",
targetConnection: "目标连接",
targetDatabase: "目标数据库",
targetSchema: "目标 Schema",
+1
View File
@@ -4303,6 +4303,7 @@ export default withEnglishFallback({
sourceConnection: "來源連線",
sourceDatabase: "來源資料庫",
sourceSchema: "來源 Schema",
swap: "交換來源與目標",
targetConnection: "目標連線",
targetDatabase: "目標資料庫",
targetSchema: "目標 Schema",