From d0f8bd0f246362c85e0d90676ed2aab11604dbc9 Mon Sep 17 00:00:00 2001 From: zipg Date: Tue, 15 Sep 2026 20:08:26 +0800 Subject: [PATCH] feat(data-compare): support recompare and endpoint distinction --- .../src/components/diff/DataCompareDialog.vue | 23 ++++++++--- .../DataCompareDialog.prefill.spec.ts | 41 +++++++++++++++++++ apps/desktop/src/i18n/locales/az.ts | 1 + apps/desktop/src/i18n/locales/en.ts | 1 + apps/desktop/src/i18n/locales/es.ts | 1 + apps/desktop/src/i18n/locales/it.ts | 1 + apps/desktop/src/i18n/locales/ja.ts | 1 + apps/desktop/src/i18n/locales/ko.ts | 1 + apps/desktop/src/i18n/locales/pt-BR.ts | 1 + apps/desktop/src/i18n/locales/tr.ts | 1 + apps/desktop/src/i18n/locales/zh-CN.ts | 1 + apps/desktop/src/i18n/locales/zh-TW.ts | 1 + 12 files changed, 68 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/components/diff/DataCompareDialog.vue b/apps/desktop/src/components/diff/DataCompareDialog.vue index 19764e1b30..d4ee57133a 100644 --- a/apps/desktop/src/components/diff/DataCompareDialog.vue +++ b/apps/desktop/src/components/diff/DataCompareDialog.vue @@ -32,7 +32,7 @@ import { import * as api from "@/lib/backend/api"; import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard"; import TableMultiSelect from "@/components/diff/TableMultiSelect.vue"; -import { ArrowLeftRight, CheckSquare, ChevronDown, ChevronRight, Copy, GitCompareArrows, Loader2, Play, Square } from "@lucide/vue"; +import { ArrowLeftRight, CheckSquare, ChevronDown, ChevronRight, Copy, GitCompareArrows, Loader2, Play, RotateCcw, Square } from "@lucide/vue"; const PREVIEW_LIMIT_OPTIONS = [50, 100, 200, 500]; const SYNC_EXECUTE_BATCH_SIZE = 500; @@ -510,7 +510,7 @@ async function rebuildSyncPlan() { } function startCompare(): void { - if (!canCompare.value || comparing.value) return; + if (!canCompare.value || comparing.value || executing.value) return; const tasks = buildCompareTasks(); if (tasks.length === 0) { toast(t("dataCompare.noComparableTables"), 5000); @@ -785,8 +785,11 @@ onBeforeUnmount(() => {
-
- +
+
+ S + {{ t("diff.source") }} +
{
-
- +
+
+ T + {{ t("diff.target") }} +
{ + {{ compareProgressLabel || t("diff.progress.comparing") }} {{ t("diff.syncProgress", { current: executedCount, total: executeTotal }) }} diff --git a/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts b/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts index 96b8c96cfb..d918b2f48e 100644 --- a/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts +++ b/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts @@ -13,6 +13,7 @@ const mocks = vi.hoisted(() => ({ listTables: vi.fn().mockResolvedValue([{ name: "CODEX_7467_META", table_type: "TABLE" }]), getColumns: vi.fn().mockResolvedValue([{ name: "ID", data_type: "NUMBER", is_primary_key: true }]), buildDataCompareSyncPlan: vi.fn(), + executeBatch: vi.fn(), })); const sessionMocks = vi.hoisted(() => ({ @@ -58,6 +59,7 @@ vi.mock("@/lib/backend/api", () => ({ listTables: mocks.listTables, getColumns: mocks.getColumns, buildDataCompareSyncPlan: mocks.buildDataCompareSyncPlan, + executeBatch: mocks.executeBatch, })); const mountedApps: App[] = []; @@ -259,6 +261,45 @@ describe("DataCompareDialog session restore", () => { expect(document.querySelector("textarea[readonly]")?.value).toBe("INSERT 1;\nINSERT 2;"); }); + it("starts another comparison and distinguishes source and target panels after results", async () => { + mountSessionDialog(completedSession()); + + await flushAsyncSetup(); + + const recompareButton = [...document.querySelectorAll("button")].find((button) => button.textContent?.includes(i18n.global.t("dataCompare.recompare"))); + expect(recompareButton).toBeDefined(); + expect([...document.querySelectorAll("div")].filter((element) => element.classList.contains("border-blue-500/35"))).toHaveLength(1); + expect([...document.querySelectorAll("div")].filter((element) => element.classList.contains("border-emerald-500/35"))).toHaveLength(1); + + recompareButton?.click(); + await flushAsyncSetup(); + + expect(mocks.ensureConnected).toHaveBeenCalledWith("oracle-11g"); + expect(mocks.ensureConnected).toHaveBeenCalledWith("oracle-jdbc-11g"); + }); + + it("disables recompare while sync SQL is still executing against the target", async () => { + mocks.executeBatch.mockImplementation(() => new Promise(() => {})); + mountSessionDialog(completedSession()); + + await flushAsyncSetup(); + mocks.ensureConnected.mockClear(); + + const executeButton = [...document.querySelectorAll("button")].find((button) => button.textContent?.includes(i18n.global.t("diff.executeSync"))); + expect(executeButton).toBeDefined(); + executeButton?.click(); + await flushAsyncSetup(); + + const recompareButton = [...document.querySelectorAll("button")].find((button) => button.textContent?.includes(i18n.global.t("dataCompare.recompare"))); + expect(recompareButton).toBeDefined(); + expect(recompareButton?.disabled).toBe(true); + + recompareButton?.click(); + await flushAsyncSetup(); + + expect(mocks.ensureConnected).not.toHaveBeenCalledWith("oracle-11g"); + }); + it("persists the latest selection plan when the dialog closes during planning", async () => { const session = completedSession(); let resolvePlan!: (plan: DataCompareSession["syncPlan"]) => void; diff --git a/apps/desktop/src/i18n/locales/az.ts b/apps/desktop/src/i18n/locales/az.ts index 9e162c6033..5b83d06d66 100644 --- a/apps/desktop/src/i18n/locales/az.ts +++ b/apps/desktop/src/i18n/locales/az.ts @@ -6633,6 +6633,7 @@ export default withEnglishFallback({ rowCounts: "Mənbədə {source} sətir, hədəfdə {target} sətir; tam müqayisə tamamlandı", previewLimitOption: "Önbaxış: {count}", compare: "Verilənləri müqayisə et", + recompare: "Yenidən müqayisə et", summary: "Əlavə edilib: {added}, çıxarılıb: {removed}, dəyişdirilib: {modified}", batchSummary: "{tables} cədvəl müqayisə edilib: {different} fərqli, {same} eyni, {failed} uğursuz; əlavə edilib: {added}, çıxarılıb: {removed}, dəyişdirilib: {modified}", comparingTable: "Müqayisə edilir {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 36eff94317..f4312564cf 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -6820,6 +6820,7 @@ export default { rowCounts: "Source {source} rows, target {target} rows; full compare completed", previewLimitOption: "Preview {count}", compare: "Compare Data", + recompare: "Compare Again", summary: "Added {added}, removed {removed}, modified {modified}", batchSummary: "Compared {tables} tables: {different} different, {same} identical, {failed} failed; added {added}, removed {removed}, modified {modified}", comparingTable: "Comparing {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 677e6bf8f5..9c4a8ee090 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -6393,6 +6393,7 @@ export default withEnglishFallback({ rowCounts: "Origen {source} filas, destino {target} filas; comparación completa terminada", previewLimitOption: "Vista previa {count}", compare: "Comparar datos", + recompare: "Comparar de nuevo", summary: "Agregadas {added}, eliminadas {removed}, modificadas {modified}", batchSummary: "Se compararon {tables} tablas: {different} con diferencias, {same} iguales, {failed} con error; agregadas {added}, eliminadas {removed}, modificadas {modified}", comparingTable: "Comparando {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index a9f3ace671..19b09cf6fe 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -6393,6 +6393,7 @@ export default withEnglishFallback({ rowCounts: "Sorgente {source} righe, destinazione {target} righe; confronto completo completato", previewLimitOption: "Anteprima {count}", compare: "Confronta Dati", + recompare: "Confronta di nuovo", summary: "Aggiunte {added}, rimosse {removed}, modificate {modified}", batchSummary: "Confrontate {tables} tabelle: {different} diverse, {same} identiche, {failed} non riuscite; aggiunte {added}, rimosse {removed}, modificate {modified}", comparingTable: "Confronto di {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index 2a826d69cc..364bb7df0e 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -6431,6 +6431,7 @@ export default withEnglishFallback({ rowCounts: "ソース {source}行、ターゲット {target}行、完全比較が完了しました", previewLimitOption: "{count}件プレビュー", compare: "データを比較", + recompare: "再比較", summary: "追加 {added}、削除 {removed}、変更 {modified}", batchSummary: "{tables}テーブルを比較: {different}不一致、{same}一致、{failed}失敗; 追加 {added}、削除 {removed}、変更 {modified}", comparingTable: "比較中 {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts index acb03698d8..9942b322d7 100644 --- a/apps/desktop/src/i18n/locales/ko.ts +++ b/apps/desktop/src/i18n/locales/ko.ts @@ -6143,6 +6143,7 @@ export default withEnglishFallback({ rowCounts: "소스 {source}행, 대상 {target}행; 전체 비교 완료", previewLimitOption: "미리보기 {count}", compare: "데이터 비교", + recompare: "다시 비교", summary: "추가 {added}, 제거 {removed}, 수정 {modified}", batchSummary: "테이블 {tables}개 비교: {different}개 차이, {same}개 동일, {failed}개 실패; 추가 {added}, 제거 {removed}, 수정 {modified}", comparingTable: "{current}/{total} 비교 중: {table}", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index 9f26665b59..4a1d6b2e42 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -6395,6 +6395,7 @@ export default withEnglishFallback({ rowCounts: "Origem com {source} linhas, destino com {target} linhas; comparação completa concluída", previewLimitOption: "Pré-visualizar {count}", compare: "Comparar Dados", + recompare: "Comparar novamente", summary: "{added} adicionados, {removed} removidos, {modified} modificados", batchSummary: "{tables} tabelas comparadas: {different} diferentes, {same} idênticas, {failed} com falha; {added} adicionados, {removed} removidos, {modified} modificados", comparingTable: "Comparando {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/tr.ts b/apps/desktop/src/i18n/locales/tr.ts index 4ea9051462..38f65486c1 100644 --- a/apps/desktop/src/i18n/locales/tr.ts +++ b/apps/desktop/src/i18n/locales/tr.ts @@ -6515,6 +6515,7 @@ export default withEnglishFallback({ rowCounts: "Kaynak {source} satır, hedef {target} satır; tam karşılaştırma tamamlandı", previewLimitOption: "Önizleme {count}", compare: "Verileri Karşılaştır", + recompare: "Tekrar karşılaştır", summary: "{added} eklendi, {removed} kaldırıldı, {modified} değiştirildi", batchSummary: "{tables} tablo karşılaştırıldı: {different} farklı, {same} aynı, {failed} başarısız; {added} eklendi, {removed} kaldırıldı, {modified} değiştirildi", comparingTable: "Karşılaştırılıyor {current}/{total}: {table}", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index e6f23ae47d..1600b09b48 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -6794,6 +6794,7 @@ export default withEnglishFallback({ rowCounts: "源表 {source} 行,目标表 {target} 行;已完成全量比较", previewLimitOption: "预览 {count}", compare: "开始比较数据", + recompare: "重新比较", summary: "新增 {added} 行,删除 {removed} 行,修改 {modified} 行", batchSummary: "已比较 {tables} 张表:存在差异 {different} 张,一致 {same} 张,失败 {failed} 张;累计新增 {added} 行,删除 {removed} 行,修改 {modified} 行", comparingTable: "正在比较 {current}/{total}:{table}", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 1ce6f5fbee..86cd0a8bb1 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -5713,6 +5713,7 @@ export default withEnglishFallback({ rowCounts: "來源 {source} 列,目標 {target} 列;已完成完整比較", previewLimitOption: "預覽 {count}", compare: "開始比較資料", + recompare: "重新比較", summary: "新增 {added} 列,刪除 {removed} 列,修改 {modified} 列", batchSummary: "已比較 {tables} 張資料表:{different} 張有差異,{same} 張一致,{failed} 張失敗;新增 {added} 列,刪除 {removed} 列,修改 {modified} 列", comparingTable: "正在比較 {current}/{total}:{table}",