♻️ refactor(codebase): 拆分大文件并收敛模块职责

- 拆分 ConnectionModal、DataGrid、QueryEditor、App 等前端大文件

- 抽出 driver assets、v2 workbench 样式和 source-as-test 读取辅助

- 更新相关测试以覆盖拆分后的源码位置
This commit is contained in:
Syngnat
2026-06-19 23:10:00 +08:00
parent 6179c3fbd9
commit 0f67305100
33 changed files with 22113 additions and 18998 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,807 @@
import type { ConnectionConfig, SavedConnection } from "../../types";
import { resolveConnectionSecretDraft } from "../../utils/connectionSecretDraft";
import {
getConnectionTypeDefaultPort as getDefaultPortByType,
} from "../../utils/connectionTypeCatalog";
import {
isFileDatabaseType,
isMySQLCompatibleType,
supportsConnectionParamsForType,
supportsSSLClientCertificateForType,
supportsSSLForType,
} from "../../utils/connectionTypeCapabilities";
import {
buildDefaultJVMConnectionValues,
buildJVMConnectionConfig,
hasUnsupportedJVMDiagnosticTransport,
hasUnsupportedJVMEditableModes,
normalizeEditableJVMModes,
} from "../../utils/jvmConnectionConfig";
import { resolveRedisConfigDraft } from "../../utils/redisConnectionUri";
import {
normalizeAddressList,
normalizeClickHouseProtocolValue,
normalizeConnectionParamsText,
normalizeFileDbPath,
normalizeMongoSrvHostList,
normalizeOceanBaseConnectionParamsText,
normalizeOceanBaseProtocolValue,
parseClickHouseHTTPUriToValues,
parseHostPort,
parseUriToValues,
toAddress,
} from "./connectionModalUri";
type Translate = (key: string, params?: any) => string;
export type ConnectionSecretKey =
| "primaryPassword"
| "sshPassword"
| "proxyPassword"
| "httpTunnelPassword"
| "mysqlReplicaPassword"
| "mongoReplicaPassword"
| "redisSentinelPassword"
| "opaqueURI"
| "opaqueDSN";
export type ConnectionSecretClearState = Record<ConnectionSecretKey, boolean>;
export const createEmptyConnectionSecretClearState =
(): ConnectionSecretClearState => ({
primaryPassword: false,
sshPassword: false,
proxyPassword: false,
httpTunnelPassword: false,
mysqlReplicaPassword: false,
mongoReplicaPassword: false,
redisSentinelPassword: false,
opaqueURI: false,
opaqueDSN: false,
});
type BuildSavedConnectionInputParams = {
config: ConnectionConfig;
values: any;
initialValues?: SavedConnection | null;
clearSecrets: ConnectionSecretClearState;
customIconType?: string;
customIconColor?: string;
};
type GetBlockingSecretClearMessageParams = {
values: any;
clearSecrets: ConnectionSecretClearState;
initialValues?: SavedConnection | null;
translate: Translate;
};
type BuildConnectionConfigParams = {
values: any;
forPersist: boolean;
initialValues?: SavedConnection | null;
translate: Translate;
};
export const buildSavedConnectionInput = ({
config,
values,
initialValues,
clearSecrets,
customIconType,
customIconColor,
}: BuildSavedConnectionInputParams) => {
const connectionId =
initialValues?.id || config.id || Date.now().toString();
const primaryDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasPrimaryPassword,
valueInput: config.password,
clearSecret:
clearSecrets.primaryPassword ||
(initialValues?.hasPrimaryPassword === true &&
String(config.password || "") === ""),
forceClear: values.type === "mongodb" && values.savePassword === false,
});
const sshDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasSSHPassword,
valueInput: config.ssh?.password,
clearSecret: clearSecrets.sshPassword,
forceClear: !config.useSSH,
});
const proxyDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasProxyPassword,
valueInput: config.proxy?.password,
clearSecret: clearSecrets.proxyPassword,
forceClear: !config.useProxy,
});
const httpTunnelDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasHttpTunnelPassword,
valueInput: config.httpTunnel?.password,
clearSecret: clearSecrets.httpTunnelPassword,
forceClear: !config.useHttpTunnel,
});
const mysqlReplicaEnabled =
isMySQLCompatibleType(config.type) && config.topology === "replica";
const mysqlReplicaDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasMySQLReplicaPassword,
valueInput: config.mysqlReplicaPassword,
clearSecret: clearSecrets.mysqlReplicaPassword,
forceClear: !mysqlReplicaEnabled,
});
const mongoReplicaEnabled =
config.type === "mongodb" &&
config.topology === "replica" &&
values.savePassword !== false;
const mongoReplicaDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasMongoReplicaPassword,
valueInput: config.mongoReplicaPassword,
clearSecret: clearSecrets.mongoReplicaPassword,
forceClear: !mongoReplicaEnabled,
});
const redisSentinelEnabled =
config.type === "redis" &&
config.topology === "sentinel" &&
values.savePassword !== false;
const redisSentinelDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasRedisSentinelPassword,
valueInput: config.redisSentinelPassword,
clearSecret: clearSecrets.redisSentinelPassword,
forceClear: !redisSentinelEnabled,
});
const opaqueUriDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasOpaqueURI,
valueInput: config.uri,
clearSecret: clearSecrets.opaqueURI,
forceClear: values.type === "custom",
trimInput: true,
});
const opaqueDsnDraft = resolveConnectionSecretDraft({
hasSecret: initialValues?.hasOpaqueDSN,
valueInput: config.dsn,
clearSecret: clearSecrets.opaqueDSN,
forceClear: values.type !== "custom",
trimInput: true,
});
const isRedisType = values.type === "redis";
const displayHost = String(
(config as any).host || values.host || "",
).trim();
const nextName =
values.name ||
(isFileDatabaseType(values.type)
? values.type === "duckdb"
? "DuckDB DB"
: "SQLite DB"
: values.type === "redis"
? `Redis ${displayHost}`
: displayHost);
return {
id: connectionId,
name: nextName,
config: {
...config,
id: connectionId,
password: primaryDraft.value,
ssh: {
...(config.ssh || {
host: "",
port: 22,
user: "",
password: "",
keyPath: "",
}),
password: sshDraft.value,
},
proxy: {
...(config.proxy || {
type: "socks5",
host: "",
port: 1080,
user: "",
password: "",
}),
password: proxyDraft.value,
},
httpTunnel: {
...(config.httpTunnel || {
host: "",
port: 8080,
user: "",
password: "",
}),
password: httpTunnelDraft.value,
},
uri: opaqueUriDraft.value,
dsn: opaqueDsnDraft.value,
mysqlReplicaPassword: mysqlReplicaDraft.value,
mongoReplicaPassword: mongoReplicaDraft.value,
redisSentinelPassword: redisSentinelDraft.value,
},
includeDatabases: values.includeDatabases,
includeRedisDatabases: isRedisType
? values.includeRedisDatabases
: undefined,
iconType: customIconType || "",
iconColor: customIconColor || "",
clearPrimaryPassword: primaryDraft.clearStoredSecret,
clearSSHPassword: sshDraft.clearStoredSecret,
clearProxyPassword: proxyDraft.clearStoredSecret,
clearHttpTunnelPassword: httpTunnelDraft.clearStoredSecret,
clearMySQLReplicaPassword: mysqlReplicaDraft.clearStoredSecret,
clearMongoReplicaPassword: mongoReplicaDraft.clearStoredSecret,
clearRedisSentinelPassword: redisSentinelDraft.clearStoredSecret,
clearOpaqueURI: opaqueUriDraft.clearStoredSecret,
clearOpaqueDSN: opaqueDsnDraft.clearStoredSecret,
};
};
export const getBlockingSecretClearMessage = ({
values,
clearSecrets,
initialValues,
translate: t,
}: GetBlockingSecretClearMessageParams): string | null => {
if (
clearSecrets.primaryPassword &&
values.type !== "custom" &&
!isFileDatabaseType(values.type) &&
String(values.password ?? "") === ""
) {
return t("connection.modal.secret.blocking.primary");
}
if (
clearSecrets.sshPassword &&
values.useSSH &&
String(values.sshPassword ?? "") === ""
) {
return t("connection.modal.secret.blocking.ssh");
}
if (
clearSecrets.proxyPassword &&
values.useProxy &&
!values.useHttpTunnel &&
String(values.proxyPassword ?? "") === ""
) {
return t("connection.modal.secret.blocking.proxy");
}
if (
clearSecrets.httpTunnelPassword &&
values.useHttpTunnel &&
String(values.httpTunnelPassword ?? "") === ""
) {
return t("connection.modal.secret.blocking.httpTunnel");
}
if (
clearSecrets.mysqlReplicaPassword &&
isMySQLCompatibleType(values.type) &&
values.mysqlTopology === "replica" &&
String(values.mysqlReplicaPassword ?? "") === ""
) {
return t("connection.modal.secret.blocking.mysqlReplica");
}
if (
clearSecrets.mongoReplicaPassword &&
values.type === "mongodb" &&
values.mongoTopology === "replica" &&
String(values.mongoReplicaPassword ?? "") === ""
) {
return t("connection.modal.secret.blocking.mongoReplica");
}
if (
clearSecrets.redisSentinelPassword &&
values.type === "redis" &&
values.redisTopology === "sentinel" &&
String(values.redisSentinelPassword ?? "") === ""
) {
return t("connection.modal.secret.blocking.redis_sentinel");
}
if (
values.type === "mongodb" &&
values.savePassword === false &&
initialValues?.hasPrimaryPassword &&
String(values.password ?? "") === ""
) {
return t("connection.modal.secret.blocking.mongoPrimary");
}
return null;
};
export const buildConnectionConfig = async ({
values,
forPersist,
initialValues,
translate: t,
}: BuildConnectionConfigParams): Promise<ConnectionConfig> => {
const mergedValues = { ...values };
if (
String(mergedValues.type || "")
.trim()
.toLowerCase() === "jvm"
) {
if (
hasUnsupportedJVMEditableModes({
allowedModes: mergedValues.jvmAllowedModes,
preferredMode: mergedValues.jvmPreferredMode,
})
) {
throw new Error(t("connection.modal.jvm.unsupportedMode.saveTest"));
}
if (
hasUnsupportedJVMDiagnosticTransport(
mergedValues.jvmDiagnosticTransport,
)
) {
throw new Error(
t("connection.modal.jvm.unsupportedTransport.saveTest"),
);
}
const existingDiagnostic = initialValues?.config?.jvm?.diagnostic;
if (
mergedValues.jvmDiagnosticEnabled === undefined &&
existingDiagnostic?.enabled !== undefined
) {
mergedValues.jvmDiagnosticEnabled = existingDiagnostic.enabled;
}
if (
String(mergedValues.jvmDiagnosticTransport || "").trim() === "" &&
existingDiagnostic?.transport
) {
mergedValues.jvmDiagnosticTransport = existingDiagnostic.transport;
}
if (
String(mergedValues.jvmDiagnosticBaseUrl || "").trim() === "" &&
existingDiagnostic?.baseUrl
) {
mergedValues.jvmDiagnosticBaseUrl = existingDiagnostic.baseUrl;
}
if (
String(mergedValues.jvmDiagnosticTargetId || "").trim() === "" &&
existingDiagnostic?.targetId
) {
mergedValues.jvmDiagnosticTargetId = existingDiagnostic.targetId;
}
if (
String(mergedValues.jvmDiagnosticApiKey || "").trim() === "" &&
existingDiagnostic?.apiKey
) {
mergedValues.jvmDiagnosticApiKey = existingDiagnostic.apiKey;
}
if (
mergedValues.jvmDiagnosticAllowObserveCommands === undefined &&
existingDiagnostic?.allowObserveCommands !== undefined
) {
mergedValues.jvmDiagnosticAllowObserveCommands =
existingDiagnostic.allowObserveCommands;
}
if (
mergedValues.jvmDiagnosticAllowTraceCommands === undefined &&
existingDiagnostic?.allowTraceCommands !== undefined
) {
mergedValues.jvmDiagnosticAllowTraceCommands =
existingDiagnostic.allowTraceCommands;
}
if (
mergedValues.jvmDiagnosticAllowMutatingCommands === undefined &&
existingDiagnostic?.allowMutatingCommands !== undefined
) {
mergedValues.jvmDiagnosticAllowMutatingCommands =
existingDiagnostic.allowMutatingCommands;
}
if (
(mergedValues.jvmDiagnosticTimeoutSeconds === undefined ||
mergedValues.jvmDiagnosticTimeoutSeconds === null ||
mergedValues.jvmDiagnosticTimeoutSeconds === "") &&
Number(existingDiagnostic?.timeoutSeconds) > 0
) {
mergedValues.jvmDiagnosticTimeoutSeconds = Number(
existingDiagnostic?.timeoutSeconds,
);
}
const resolvedJvmAllowedModes = normalizeEditableJVMModes(
mergedValues.jvmAllowedModes,
);
const resolvedJvmTimeout = Number(mergedValues.timeout || 30);
const preferredJvmMode = String(mergedValues.jvmPreferredMode || "")
.trim()
.toLowerCase();
const resolvedJvmPreferredMode =
resolvedJvmAllowedModes.find((mode) => mode === preferredJvmMode) ||
resolvedJvmAllowedModes[0];
return buildJVMConnectionConfig({
...buildDefaultJVMConnectionValues(),
...mergedValues,
jvmAllowedModes: resolvedJvmAllowedModes,
jvmPreferredMode: resolvedJvmPreferredMode,
jvmEndpointEnabled: resolvedJvmAllowedModes.includes("endpoint"),
jvmAgentEnabled: resolvedJvmAllowedModes.includes("agent"),
timeout: resolvedJvmTimeout,
jvmEndpointTimeoutSeconds: resolvedJvmTimeout,
});
}
const parsedUriValues = parseUriToValues(
mergedValues.uri,
mergedValues.type,
);
const isEmptyField = (value: unknown) =>
value === undefined ||
value === null ||
value === "" ||
value === 0 ||
(Array.isArray(value) && value.length === 0);
if (parsedUriValues) {
Object.entries(parsedUriValues).forEach(([key, value]) => {
if (
key === "clickHouseProtocol" &&
normalizeClickHouseProtocolValue((mergedValues as any)[key]) ===
"auto" &&
normalizeClickHouseProtocolValue(value) !== "auto"
) {
(mergedValues as any)[key] = value;
return;
}
if (isEmptyField((mergedValues as any)[key])) {
(mergedValues as any)[key] = value;
}
});
}
const type = String(mergedValues.type || "").toLowerCase();
const defaultPort = getDefaultPortByType(type);
const selectedOceanBaseProtocol =
type === "oceanbase"
? normalizeOceanBaseProtocolValue(mergedValues.oceanBaseProtocol)
: "mysql";
if (type === "clickhouse") {
const requestedProtocol = normalizeClickHouseProtocolValue(
mergedValues.clickHouseProtocol,
);
const hostSchemeValues = parseClickHouseHTTPUriToValues(
mergedValues.host,
Number(mergedValues.port || defaultPort),
);
if (hostSchemeValues) {
mergedValues.host = hostSchemeValues.host;
mergedValues.port = hostSchemeValues.port;
if (requestedProtocol !== "native") {
mergedValues.clickHouseProtocol = "http";
mergedValues.useSSL = hostSchemeValues.useSSL;
mergedValues.sslMode = hostSchemeValues.sslMode;
} else {
mergedValues.clickHouseProtocol = "native";
}
if (isEmptyField(mergedValues.user)) {
mergedValues.user = hostSchemeValues.user;
}
if (isEmptyField(mergedValues.password)) {
mergedValues.password = hostSchemeValues.password;
}
if (isEmptyField(mergedValues.database)) {
mergedValues.database = hostSchemeValues.database;
}
}
}
const isFileDbType = isFileDatabaseType(type);
const sslCapableType = supportsSSLForType(type);
// Redis 默认不展示用户名字段;若 URI 可解析则以 URI 为准覆盖 user
// 同时清理历史默认值 root避免 go-redis 发送 ACL AUTH(user, pass) 导致 WRONGPASS。
if (type === "redis") {
if (
parsedUriValues &&
Object.prototype.hasOwnProperty.call(parsedUriValues, "user")
) {
mergedValues.user = String((parsedUriValues as any).user || "");
} else if (String(mergedValues.user || "").trim() === "root") {
mergedValues.user = "";
}
}
const sslModeRaw = String(mergedValues.sslMode || "preferred")
.trim()
.toLowerCase();
const sslMode: "preferred" | "required" | "skip-verify" | "disable" =
sslModeRaw === "required"
? "required"
: sslModeRaw === "skip-verify"
? "skip-verify"
: sslModeRaw === "disable"
? "disable"
: "preferred";
const effectiveUseSSL = sslCapableType && !!mergedValues.useSSL;
const sslCAPath = sslCapableType
? String(mergedValues.sslCAPath || "").trim()
: "";
const sslCertPath = sslCapableType
? String(mergedValues.sslCertPath || "").trim()
: "";
const sslKeyPath = sslCapableType
? String(mergedValues.sslKeyPath || "").trim()
: "";
if (type === "dameng" && effectiveUseSSL && (!sslCertPath || !sslKeyPath)) {
throw new Error(t("connection.modal.validation.ssl.damengRequired"));
}
if (effectiveUseSSL && supportsSSLClientCertificateForType(type) && (!!sslCertPath !== !!sslKeyPath)) {
throw new Error(t("connection.modal.validation.ssl.clientPairRequired"));
}
let primaryHost = "localhost";
let primaryPort = defaultPort;
if (isFileDbType) {
// 文件型数据库sqlite/duckdb这里的 host 即数据库文件路径,不应参与 host:port 拼接与解析。
primaryHost = normalizeFileDbPath(String(mergedValues.host || "").trim());
primaryPort = 0;
} else {
const parsedPrimary = parseHostPort(
toAddress(
mergedValues.host || "localhost",
Number(mergedValues.port || defaultPort),
defaultPort,
),
defaultPort,
);
primaryHost = parsedPrimary?.host || "localhost";
primaryPort = parsedPrimary?.port || defaultPort;
}
let hosts: string[] = [];
let topology: "single" | "replica" | "cluster" | "sentinel" | undefined;
let replicaSet = "";
let authSource = "";
let readPreference = "";
let mysqlReplicaUser = "";
let mysqlReplicaPassword = "";
let mongoSrvEnabled = false;
let mongoAuthMechanism = "";
let mongoReplicaUser = "";
let mongoReplicaPassword = "";
let redisSentinelMaster = "";
let redisSentinelUser = "";
let redisSentinelPassword = "";
const savePassword =
type === "mongodb" ? mergedValues.savePassword !== false : true;
if (isMySQLCompatibleType(type) && selectedOceanBaseProtocol !== "oracle") {
const replicas =
mergedValues.mysqlTopology === "replica"
? normalizeAddressList(mergedValues.mysqlReplicaHosts, defaultPort)
: [];
const allHosts = normalizeAddressList(
[`${primaryHost}:${primaryPort}`, ...replicas],
defaultPort,
);
if (mergedValues.mysqlTopology === "replica" || allHosts.length > 1) {
hosts = allHosts;
topology = "replica";
mysqlReplicaUser = String(mergedValues.mysqlReplicaUser || "").trim();
mysqlReplicaPassword = String(mergedValues.mysqlReplicaPassword || "");
} else {
topology = "single";
}
}
if (type === "kafka") {
const brokers =
mergedValues.kafkaTopology === "cluster"
? normalizeAddressList(mergedValues.kafkaHosts, defaultPort)
: [];
const allHosts = normalizeAddressList(
[`${primaryHost}:${primaryPort}`, ...brokers],
defaultPort,
);
if (mergedValues.kafkaTopology === "cluster" || allHosts.length > 1) {
hosts = allHosts;
topology = "cluster";
} else {
topology = "single";
}
}
if (type === "mqtt") {
const brokers =
mergedValues.mqttTopology === "cluster"
? normalizeAddressList(mergedValues.mqttHosts, defaultPort)
: [];
const allHosts = normalizeAddressList(
[`${primaryHost}:${primaryPort}`, ...brokers],
defaultPort,
);
if (mergedValues.mqttTopology === "cluster" || allHosts.length > 1) {
hosts = allHosts;
topology = "cluster";
} else {
topology = "single";
}
}
if (type === "rocketmq") {
const nameservers =
mergedValues.rocketmqTopology === "cluster"
? normalizeAddressList(mergedValues.rocketmqHosts, defaultPort)
: [];
const allHosts = normalizeAddressList(
[`${primaryHost}:${primaryPort}`, ...nameservers],
defaultPort,
);
if (mergedValues.rocketmqTopology === "cluster" || allHosts.length > 1) {
hosts = allHosts;
topology = "cluster";
} else {
topology = "single";
}
}
if (type === "mongodb") {
mongoSrvEnabled = !!mergedValues.mongoSrv;
const extraHosts =
mergedValues.mongoTopology === "replica"
? mongoSrvEnabled
? normalizeMongoSrvHostList(mergedValues.mongoHosts, defaultPort)
: normalizeAddressList(mergedValues.mongoHosts, defaultPort)
: [];
const primarySeed = mongoSrvEnabled
? primaryHost
: `${primaryHost}:${primaryPort}`;
const allHosts = mongoSrvEnabled
? normalizeMongoSrvHostList([primarySeed, ...extraHosts], defaultPort)
: normalizeAddressList([primarySeed, ...extraHosts], defaultPort);
if (
mergedValues.mongoTopology === "replica" ||
allHosts.length > 1 ||
mergedValues.mongoReplicaSet
) {
hosts = allHosts;
topology = "replica";
mongoReplicaUser = String(mergedValues.mongoReplicaUser || "").trim();
mongoReplicaPassword = String(mergedValues.mongoReplicaPassword || "");
} else {
topology = "single";
}
replicaSet = String(mergedValues.mongoReplicaSet || "").trim();
authSource = String(
mergedValues.mongoAuthSource || mergedValues.database || "admin",
).trim();
readPreference = String(
mergedValues.mongoReadPreference || "primary",
).trim();
mongoAuthMechanism = String(mergedValues.mongoAuthMechanism || "")
.trim()
.toUpperCase();
}
if (type === "redis") {
const redisDraft = resolveRedisConfigDraft(
mergedValues,
primaryHost,
primaryPort,
defaultPort,
);
primaryPort = redisDraft.primaryPort;
hosts = redisDraft.hosts;
topology = redisDraft.topology;
redisSentinelMaster = redisDraft.redisSentinelMaster;
redisSentinelUser = redisDraft.redisSentinelUser;
redisSentinelPassword = redisDraft.redisSentinelPassword;
mergedValues.redisDB = redisDraft.redisDB;
}
const sshConfig = mergedValues.useSSH
? {
host: mergedValues.sshHost,
port: Number(mergedValues.sshPort),
user: mergedValues.sshUser,
password: mergedValues.sshPassword || "",
keyPath: mergedValues.sshKeyPath || "",
}
: { host: "", port: 22, user: "", password: "", keyPath: "" };
const effectiveUseHttpTunnel =
!isFileDbType && !!mergedValues.useHttpTunnel;
const effectiveUseProxy =
!isFileDbType && !!mergedValues.useProxy && !effectiveUseHttpTunnel;
const proxyTypeRaw = String(
mergedValues.proxyType || "socks5",
).toLowerCase();
const proxyType: "socks5" | "http" =
proxyTypeRaw === "http" ? "http" : "socks5";
const proxyConfig: NonNullable<ConnectionConfig["proxy"]> =
effectiveUseProxy
? {
type: proxyType,
host: String(mergedValues.proxyHost || "").trim(),
port: Number(
mergedValues.proxyPort || (proxyTypeRaw === "http" ? 8080 : 1080),
),
user: String(mergedValues.proxyUser || "").trim(),
password: mergedValues.proxyPassword || "",
}
: {
type: "socks5",
host: "",
port: 1080,
user: "",
password: "",
};
const httpTunnelConfig: NonNullable<ConnectionConfig["httpTunnel"]> =
effectiveUseHttpTunnel
? {
host: String(mergedValues.httpTunnelHost || "").trim(),
port: Number(mergedValues.httpTunnelPort || 8080),
user: String(mergedValues.httpTunnelUser || "").trim(),
password: mergedValues.httpTunnelPassword || "",
}
: {
host: "",
port: 8080,
user: "",
password: "",
};
if (effectiveUseHttpTunnel) {
if (!httpTunnelConfig.host) {
throw new Error(t("connection.modal.validation.httpTunnel.hostRequired"));
}
if (
!Number.isFinite(httpTunnelConfig.port) ||
httpTunnelConfig.port <= 0 ||
httpTunnelConfig.port > 65535
) {
throw new Error(t("connection.modal.validation.httpTunnel.portRange"));
}
}
const keepPassword = !forPersist || savePassword;
const normalizedConnectionParams = supportsConnectionParamsForType(type)
? type === "oceanbase"
? normalizeOceanBaseConnectionParamsText(
mergedValues.connectionParams,
selectedOceanBaseProtocol,
)
: normalizeConnectionParamsText(mergedValues.connectionParams)
: "";
return {
type: mergedValues.type,
host: primaryHost,
port: Number(primaryPort || 0),
user: mergedValues.user || "",
password: keepPassword ? mergedValues.password || "" : "",
savePassword: savePassword,
database: mergedValues.database || "",
useSSL: effectiveUseSSL,
sslMode: effectiveUseSSL ? sslMode : "disable",
sslCAPath: sslCAPath,
sslCertPath: sslCertPath,
sslKeyPath: sslKeyPath,
useSSH: !!mergedValues.useSSH,
ssh: sshConfig,
useProxy: effectiveUseProxy,
proxy: proxyConfig,
useHttpTunnel: effectiveUseHttpTunnel,
httpTunnel: httpTunnelConfig,
driver: mergedValues.driver,
dsn: mergedValues.dsn,
connectionParams: normalizedConnectionParams,
timeout: Number(mergedValues.timeout || 30),
redisDB: Number.isFinite(Number(mergedValues.redisDB))
? Math.max(0, Math.trunc(Number(mergedValues.redisDB)))
: 0,
redisSentinelMaster: redisSentinelMaster,

File diff suppressed because it is too large Load Diff