From c8a16708caa687b0331eab29d433992eb2ae4ff9 Mon Sep 17 00:00:00 2001 From: t8y2 Date: Fri, 16 Oct 2026 18:40:54 +0800 Subject: [PATCH] feat(connection): group GBase 8c into the GBase picker entry Closes #12483 --- .../connection/ConnectionDialog.vue | 18 +++++++++++------ .../gbase8sConnectionDialog.spec.ts | 8 ++++++-- .../connection/gbaseProfiles.spec.ts | 19 ++++++++++++++++++ .../src/lib/connection/gbaseProfiles.ts | 20 +++++++++++++++++++ .../src/types/generated/connectionProfiles.ts | 1 - .../connection-types/profiles/catalog.yaml | 1 - 6 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 apps/desktop/src/lib/__tests__/connection/gbaseProfiles.spec.ts create mode 100644 apps/desktop/src/lib/connection/gbaseProfiles.ts diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index e21840a71e..55525adc2c 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -77,6 +77,7 @@ import { isTauriRuntime } from "@/lib/backend/tauriRuntime"; import { isWindows } from "@/lib/backend/platform"; import { applyMeilisearchBasePathToExternalConfig, applyParsedConnectionUrl, normalizeMongoConnectionString, parseConnectionUrl } from "@/lib/connection/connectionUrl"; import { hasGbase8cConnectionDatabase } from "@/lib/connection/gbase8cDatabase"; +import { type GbaseProfile, gbaseProfileFromConfig, isGbaseProfile } from "@/lib/connection/gbaseProfiles"; import { loadVisibleDatabasesPickerNames } from "@/lib/connection/visibleDatabasesPickerLoad"; import { hasXuguConnectionDatabase } from "@/lib/connection/xuguDatabase"; import { @@ -1290,7 +1291,7 @@ function selectedProfile() { icon: "plugin", }; } - const profile = selectedType.value === "gbase" && (form.value.driver_profile === "gbase8a" || form.value.driver_profile === "gbase8s") ? form.value.driver_profile : selectedType.value; + const profile = selectedType.value === "gbase" ? gbaseProfileFromConfig(form.value) : selectedType.value; return driverProfiles[profile] ?? driverProfiles.mysql; } @@ -3079,7 +3080,9 @@ function switchOceanbaseMode(mode: "mysql" | "oracle") { resetTestState(); } -function switchGbaseProfile(profile: "gbase8a" | "gbase8s") { +const gbaseFormProfile = computed(() => gbaseProfileFromConfig(form.value)); + +function switchGbaseProfile(profile: GbaseProfile) { applyProfile(profile, false); selectedType.value = "gbase"; resetTestState(); @@ -3261,7 +3264,7 @@ watch( if (profile === "oceanbase") { oceanbaseSubMode.value = oceanbaseMode; } - if (profile === "gbase8a" || profile === "gbase8s") { + if (isGbaseProfile(profile)) { selectedType.value = "gbase"; } dremioConnectionMode.value = profile === "dremio" ? dremioConnectionModeForConfig(config) : "legacy"; @@ -4664,6 +4667,8 @@ function applyConnectionUrlToForm(input: string): boolean { if (parsed.driverProfile === "oceanbase-oracle") { oceanbaseSubMode.value = "oracle"; selectedType.value = "oceanbase"; + } else if (isGbaseProfile(parsed.driverProfile)) { + selectedType.value = "gbase"; } else { selectedType.value = parsed.driverProfile; } @@ -6336,7 +6341,7 @@ function applyConnectionDraftToForm(draft: ConnectionDeepLinkDraft) { oceanbaseSubMode.value = "oracle"; selectedType.value = "oceanbase"; } - if (draft.driverProfile === "gbase8a" || draft.driverProfile === "gbase8s") { + if (isGbaseProfile(draft.driverProfile)) { selectedType.value = "gbase"; } customDriverName.value = isCustomCompatibleProfile() ? draft.driverLabel : ""; @@ -7404,8 +7409,9 @@ function openExternalUrl(url: string) {
- - + + +
diff --git a/apps/desktop/src/lib/__tests__/connection/gbase8sConnectionDialog.spec.ts b/apps/desktop/src/lib/__tests__/connection/gbase8sConnectionDialog.spec.ts index 4eeb385536..cc4ddaf267 100644 --- a/apps/desktop/src/lib/__tests__/connection/gbase8sConnectionDialog.spec.ts +++ b/apps/desktop/src/lib/__tests__/connection/gbase8sConnectionDialog.spec.ts @@ -2,6 +2,7 @@ import { readFileSync } from "node:fs"; import { parse } from "vue/compiler-sfc"; import ts from "typescript"; import { describe, expect, it } from "vitest"; +import { gbaseProfileFromConfig } from "@/lib/connection/gbaseProfiles"; const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8"); const parsedDialog = parse(dialogSource, { filename: "ConnectionDialog.vue" }); @@ -18,17 +19,19 @@ function selectedProfileHarness(selectedTypeValue: string, driverProfile: string }).outputText; // The merged dialog checks plugin providers before the profile table; the // plugin branch is stubbed out so this harness pins the GBase profile path. - const selectedProfile = new Function("driverProfiles", "selectedType", "form", "parsePluginConnectionProviderOptionValue", "selectedPluginProvider", `${javascript}\nreturn selectedProfile;`)( + const selectedProfile = new Function("driverProfiles", "selectedType", "form", "parsePluginConnectionProviderOptionValue", "selectedPluginProvider", "gbaseProfileFromConfig", `${javascript}\nreturn selectedProfile;`)( { mysql: { label: "MySQL" }, gbase: { label: "南大通用 GBase 8a" }, gbase8a: { label: "南大通用 GBase 8a" }, gbase8s: { label: "南大通用 GBase 8s" }, + gbase8c: { label: "南大通用 GBase 8c" }, }, { value: selectedTypeValue }, - { value: { driver_profile: driverProfile } }, + { value: { db_type: driverProfile === "gbase8c" ? "gbase8c" : "gbase", driver_profile: driverProfile } }, () => null, { value: null }, + gbaseProfileFromConfig, ) as () => { label: string }; return selectedProfile(); } @@ -37,6 +40,7 @@ describe("GBase 8s connection dialog", () => { it.each([ ["gbase8a", "南大通用 GBase 8a"], ["gbase8s", "南大通用 GBase 8s"], + ["gbase8c", "南大通用 GBase 8c"], ])("shows the active %s profile in the merged GBase type field", (profile, label) => { expect(selectedProfileHarness("gbase", profile).label).toBe(label); }); diff --git a/apps/desktop/src/lib/__tests__/connection/gbaseProfiles.spec.ts b/apps/desktop/src/lib/__tests__/connection/gbaseProfiles.spec.ts new file mode 100644 index 0000000000..d191b9a838 --- /dev/null +++ b/apps/desktop/src/lib/__tests__/connection/gbaseProfiles.spec.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from "vitest"; +import { gbaseProfileFromConfig, isGbaseProfile } from "@/lib/connection/gbaseProfiles"; + +describe("gbaseProfiles", () => { + it("recognizes the three GBase toggle profiles", () => { + expect(["gbase8a", "gbase8s", "gbase8c"].every(isGbaseProfile)).toBe(true); + expect(isGbaseProfile("gbase")).toBe(false); + expect(isGbaseProfile(undefined)).toBe(false); + }); + + it("resolves the toggle profile from a saved connection", () => { + expect(gbaseProfileFromConfig({ db_type: "gbase8c", driver_profile: "gbase8c" })).toBe("gbase8c"); + expect(gbaseProfileFromConfig({ db_type: "gbase8c" })).toBe("gbase8c"); + expect(gbaseProfileFromConfig({ db_type: "gbase", driver_profile: "gbase8s" })).toBe("gbase8s"); + expect(gbaseProfileFromConfig({ db_type: "gbase", driver_profile: "gbase8a" })).toBe("gbase8a"); + expect(gbaseProfileFromConfig({ db_type: "gbase", driver_profile: "gbase" })).toBe("gbase8a"); + expect(gbaseProfileFromConfig({ db_type: "gbase" })).toBe("gbase8a"); + }); +}); diff --git a/apps/desktop/src/lib/connection/gbaseProfiles.ts b/apps/desktop/src/lib/connection/gbaseProfiles.ts new file mode 100644 index 0000000000..295a5ff729 --- /dev/null +++ b/apps/desktop/src/lib/connection/gbaseProfiles.ts @@ -0,0 +1,20 @@ +import type { ConnectionConfig } from "@/types/database"; + +/** + * GBase 8a / 8s / 8c share one picker entry and one version toggle, but they are + * different engines: 8a and 8s are profiles of the `gbase` db type, while 8c is + * PostgreSQL-shaped and keeps its own `gbase8c` db type (the same split as + * OceanBase MySQL/Oracle mode). The toggle therefore switches `db_type` too. + */ +export const GBASE_PROFILES = ["gbase8a", "gbase8s", "gbase8c"] as const; + +export type GbaseProfile = (typeof GBASE_PROFILES)[number]; + +export function isGbaseProfile(value: string | undefined | null): value is GbaseProfile { + return GBASE_PROFILES.includes(value as GbaseProfile); +} + +export function gbaseProfileFromConfig(config: Pick): GbaseProfile { + if (config.db_type === "gbase8c" || config.driver_profile === "gbase8c") return "gbase8c"; + return config.driver_profile === "gbase8s" ? "gbase8s" : "gbase8a"; +} diff --git a/apps/desktop/src/types/generated/connectionProfiles.ts b/apps/desktop/src/types/generated/connectionProfiles.ts index 731a2e38f8..fbb378348f 100644 --- a/apps/desktop/src/types/generated/connectionProfiles.ts +++ b/apps/desktop/src/types/generated/connectionProfiles.ts @@ -287,7 +287,6 @@ export const CONNECTION_PICKER_OPTIONS = [ { value: "firebird", label: "Firebird", category: "sql" }, { value: "exasol", label: "Exasol", category: "analytics" }, { value: "gbase", label: "南大通用 GBase", category: "domestic" }, - { value: "gbase8c", label: "南大通用 GBase 8c", category: "domestic" }, { value: "opengauss", label: "openGauss", category: "domestic" }, { value: "gaussdb", label: "GaussDB", category: "domestic" }, { value: "kwdb", label: "KWDB", category: "domestic" }, diff --git a/plugins/connection-types/profiles/catalog.yaml b/plugins/connection-types/profiles/catalog.yaml index 0f428e1982..2d3a4443ee 100644 --- a/plugins/connection-types/profiles/catalog.yaml +++ b/plugins/connection-types/profiles/catalog.yaml @@ -323,7 +323,6 @@ profiles: icon: gbase port: 5432 user: gbase - category: domestic - id: opengauss dbType: opengauss label: openGauss