diff --git a/apps/desktop/src/components/diff/DataCompareDialog.vue b/apps/desktop/src/components/diff/DataCompareDialog.vue index e21283e0ce..d249e934e1 100644 --- a/apps/desktop/src/components/diff/DataCompareDialog.vue +++ b/apps/desktop/src/components/diff/DataCompareDialog.vue @@ -7,7 +7,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import SearchableSelect from "@/components/ui/searchable-select/SearchableSelect.vue"; -import ConnectionGroupBadge from "@/components/connection/ConnectionGroupBadge.vue"; +import ConnectionTreeSelect from "@/components/connection/ConnectionTreeSelect.vue"; import { useConnectionStore } from "@/stores/connectionStore"; import { useToast } from "@/composables/useToast"; import { databaseOptionsForConnection, fetchNamespaceOptionsForConnection } from "@/composables/useDatabaseOptions"; @@ -18,7 +18,6 @@ import { inferCompareKeyColumns } from "@/lib/dataGrid/dataCompare"; import type { ColumnInfo, DatabaseType } from "@/types/database"; import * as api from "@/lib/backend/api"; import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard"; -import DatabaseIcon from "@/components/icons/DatabaseIcon.vue"; import TableMultiSelect from "@/components/diff/TableMultiSelect.vue"; import { ArrowLeftRight, CheckSquare, ChevronDown, ChevronRight, Copy, GitCompareArrows, Loader2, Play, Square } from "@lucide/vue"; @@ -208,11 +207,6 @@ function emptySyncPlan(): DataCompareSyncPlan { }; } -function connectionIconType(connectionId: string) { - const config = store.getConfig(connectionId); - return config?.driver_profile || config?.db_type || "mysql"; -} - function targetDatabaseType(): DatabaseType | undefined { return store.getConfig(targetConnectionId.value)?.db_type; } @@ -892,25 +886,16 @@ watch(
- - - + trigger-class="dbx-diff-connection-trigger h-8 w-full max-w-none justify-between gap-1.5 rounded-md border border-input bg-transparent px-2.5 text-xs shadow-none hover:bg-muted/40 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 dark:bg-input/30 dark:hover:bg-input/50" + list-class="w-[var(--reka-popover-trigger-width)]" + /> - - - + trigger-class="dbx-diff-connection-trigger h-8 w-full max-w-none justify-between gap-1.5 rounded-md border border-input bg-transparent px-2.5 text-xs shadow-none hover:bg-muted/40 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 dark:bg-input/30 dark:hover:bg-input/50" + list-class="w-[var(--reka-popover-trigger-width)]" + /> - - - + trigger-class="dbx-diff-connection-trigger h-8 w-full max-w-none justify-between gap-1.5 rounded-md border border-input bg-transparent px-2.5 text-xs shadow-none hover:bg-muted/40 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 dark:bg-input/30 dark:hover:bg-input/50" + list-class="w-[var(--reka-popover-trigger-width)]" + />
@@ -479,26 +470,17 @@ async function fetchDbVersion(connectionId: string, database: string, schema: st
- - - + trigger-class="dbx-diff-connection-trigger h-8 w-full max-w-none justify-between gap-1.5 rounded-md border border-input bg-transparent px-2.5 text-xs shadow-none hover:bg-muted/40 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 dark:bg-input/30 dark:hover:bg-input/50" + list-class="w-[var(--reka-popover-trigger-width)]" + />
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 844c3b40a8..cd2512d5b8 100644 --- a/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts +++ b/apps/desktop/src/components/diff/__tests__/DataCompareDialog.prefill.spec.ts @@ -13,15 +13,6 @@ const mocks = vi.hoisted(() => ({ getColumns: vi.fn().mockResolvedValue([{ name: "ID", data_type: "NUMBER", is_primary_key: true }]), })); -function passthrough(tag: string) { - return defineComponent({ - inheritAttrs: false, - setup(_, { attrs, slots }) { - return () => h(tag, attrs, slots.default?.()); - }, - }); -} - vi.mock("@/stores/connectionStore", () => { const connections = [ { id: "oracle-11g", name: "Oracle XE 11g", db_type: "oracle", driver_profile: "oracle", database: "XE" }, @@ -37,16 +28,16 @@ vi.mock("@/stores/connectionStore", () => { return { useConnectionStore: () => ({ connections, + sidebarLayout: { + groups: [{ id: "oracle", name: "Oracle", collapsed: false }], + order: [{ type: "group", id: "oracle", children: connections.map((connection) => ({ type: "connection", id: connection.id })) }], + }, getConfig: (id: string) => connections.find((connection) => connection.id === id), ensureConnected: mocks.ensureConnected, }), }; }); -vi.mock("@/components/connection/ConnectionGroupBadge.vue", () => ({ - default: passthrough("span"), -})); - vi.mock("@/lib/backend/api", () => ({ listDatabases: mocks.listDatabases, listSchemas: mocks.listSchemas, @@ -94,7 +85,7 @@ describe("DataCompareDialog source prefill", () => { expect(mocks.listSchemas).toHaveBeenCalledWith("oracle-11g", "XE", true); const searchableSelectTriggers = [...document.querySelectorAll("button.dbx-searchable-select-trigger")]; - const sourceDatabaseTrigger = searchableSelectTriggers[1]; + const sourceDatabaseTrigger = searchableSelectTriggers[0]; expect(sourceDatabaseTrigger?.title).toBe("DBX_TEST"); expect(sourceDatabaseTrigger?.disabled).toBe(false); sourceDatabaseTrigger?.click(); @@ -127,13 +118,12 @@ describe("DataCompareDialog source prefill", () => { app.mount(container); await flushAsyncSetup(); - const searchableSelectTriggers = [...document.querySelectorAll("button.dbx-searchable-select-trigger")]; - const targetConnectionTrigger = searchableSelectTriggers[3]; + const targetConnectionTrigger = document.querySelectorAll("button.dbx-diff-connection-trigger")[1]; expect(targetConnectionTrigger).toBeDefined(); targetConnectionTrigger?.click(); await flushAsyncSetup(); - const jdbcConnectionOption = [...document.querySelectorAll(".dbx-searchable-select-list button")].find((button) => button.textContent?.trim() === "Oracle JDBC 11g"); + const jdbcConnectionOption = document.querySelector('[data-picker-connection="oracle-jdbc-11g"]'); expect(jdbcConnectionOption).toBeDefined(); jdbcConnectionOption?.click(); await flushAsyncSetup(); @@ -141,7 +131,7 @@ describe("DataCompareDialog source prefill", () => { expect(mocks.listSchemas).toHaveBeenCalledWith("oracle-jdbc-11g", "", true); const triggersAfterTargetLoad = [...document.querySelectorAll("button.dbx-searchable-select-trigger")]; - const targetDatabaseTrigger = triggersAfterTargetLoad[4]; + const targetDatabaseTrigger = triggersAfterTargetLoad[2]; expect(targetDatabaseTrigger?.disabled).toBe(false); targetDatabaseTrigger?.click(); await flushAsyncSetup(); diff --git a/apps/desktop/src/lib/common/__tests__/searchableSelectLayout.spec.ts b/apps/desktop/src/lib/common/__tests__/searchableSelectLayout.spec.ts index 0b8786e13f..8c41e97c93 100644 --- a/apps/desktop/src/lib/common/__tests__/searchableSelectLayout.spec.ts +++ b/apps/desktop/src/lib/common/__tests__/searchableSelectLayout.spec.ts @@ -4,6 +4,8 @@ import { describe, expect, it } from "vitest"; const searchableSelectSource = readFileSync(new URL("../../../components/ui/searchable-select/SearchableSelect.vue", import.meta.url), "utf8"); const dataTransferDialogSource = readFileSync(new URL("../../../components/transfer/DataTransferDialog.vue", import.meta.url), "utf8"); const editorToolbarSource = readFileSync(new URL("../../../components/layout/EditorToolbar.vue", import.meta.url), "utf8"); +const schemaDiffConfigStepSource = readFileSync(new URL("../../../components/diff/SchemaDiffConfigStep.vue", import.meta.url), "utf8"); +const dataCompareDialogSource = readFileSync(new URL("../../../components/diff/DataCompareDialog.vue", import.meta.url), "utf8"); describe("SearchableSelect layout", () => { it("keeps slotted option labels inside a shrinkable overflow boundary", () => { @@ -31,4 +33,14 @@ describe("SearchableSelect layout", () => { expect(editorToolbarSource).toContain(':connections="connectionStore.connections"'); expect(editorToolbarSource).toContain(':layout="connectionStore.sidebarLayout"'); }); + + it.each([ + ["schema compare", schemaDiffConfigStepSource], + ["data compare", dataCompareDialogSource], + ])("renders %s connection pickers as sidebar-like trees", (_name, source) => { + expect(source.match(/