feat(connection): group GBase 8c into the GBase picker entry

Closes #12483
This commit is contained in:
t8y2
2026-10-16 18:40:54 +08:00
parent ff6c68c3e9
commit c8a16708ca
6 changed files with 57 additions and 10 deletions
@@ -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) {
<div v-if="selectedType === 'gbase'" class="grid grid-cols-4 items-center gap-4">
<Label :class="connectionLabelSmallClass">{{ t("connection.version") }}</Label>
<div class="col-span-3 flex gap-2">
<Button size="sm" :variant="form.driver_profile === 'gbase8s' ? 'outline' : 'default'" @click="switchGbaseProfile('gbase8a')"> GBase 8a </Button>
<Button size="sm" :variant="form.driver_profile === 'gbase8s' ? 'default' : 'outline'" @click="switchGbaseProfile('gbase8s')"> GBase 8s </Button>
<Button size="sm" :variant="gbaseFormProfile === 'gbase8a' ? 'default' : 'outline'" @click="switchGbaseProfile('gbase8a')"> GBase 8a </Button>
<Button size="sm" :variant="gbaseFormProfile === 'gbase8s' ? 'default' : 'outline'" @click="switchGbaseProfile('gbase8s')"> GBase 8s </Button>
<Button size="sm" :variant="gbaseFormProfile === 'gbase8c' ? 'default' : 'outline'" @click="switchGbaseProfile('gbase8c')"> GBase 8c </Button>
</div>
</div>
@@ -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);
});
@@ -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");
});
});
@@ -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<ConnectionConfig, "db_type" | "driver_profile">): GbaseProfile {
if (config.db_type === "gbase8c" || config.driver_profile === "gbase8c") return "gbase8c";
return config.driver_profile === "gbase8s" ? "gbase8s" : "gbase8a";
}
@@ -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" },
@@ -323,7 +323,6 @@ profiles:
icon: gbase
port: 5432
user: gbase
category: domestic
- id: opengauss
dbType: opengauss
label: openGauss