fix(connection): show built-in driver update hint on connection failure (#2111)
This commit is contained in:
parent
96f265507d
commit
dab1d145bc
|
|
@ -32,7 +32,7 @@ import { isLocalFileTypeDb } from "@/lib/connectionFile";
|
|||
import { MQ_PINNED_VERSION_OPTIONS, pinnedVersionToSelection, selectionToPinnedVersion } from "@/lib/mqPinnedVersionOptions";
|
||||
import { mongodbAuthFailureHint, mongoUrlParam, setMongoUrlParam } from "@/lib/mongoConnectionOptions";
|
||||
import { copyToClipboard } from "@/lib/clipboard";
|
||||
import { showAgentDriverInstallHint, type AgentDriverInstallState } from "@/lib/agentDriverInstallHint";
|
||||
import { appendAgentDriverUpdateHint, hasAgentDriverUpdate, showAgentDriverInstallHint, type AgentDriverInstallState } from "@/lib/agentDriverInstallHint";
|
||||
import { prestoSqlBuiltinDriverPaths } from "@/lib/prestoSqlBuiltinDriver";
|
||||
import { SQLITE_DATABASE_FILE_EXTENSIONS } from "@/lib/databaseFileDetection";
|
||||
import { connectionAttemptOriginalErrorMessage, connectionAttemptTimeoutMessage, connectionAttemptTimeoutMs } from "@/lib/connectionAttemptTimeout";
|
||||
|
|
@ -757,6 +757,11 @@ function errorMessage(error: unknown): string {
|
|||
return String(error);
|
||||
}
|
||||
|
||||
function connectionErrorWithDriverUpdateHint(config: ConnectionConfig, message: string): string {
|
||||
if (!hasAgentDriverUpdate(config.db_type, agentDrivers.value, config.driver_profile)) return message;
|
||||
return appendAgentDriverUpdateHint(message, t("connection.agentDriverUpdateConnectionHint"));
|
||||
}
|
||||
|
||||
async function testConnectionWithTimeout(config: ConnectionConfig, runId: number): Promise<string> {
|
||||
const timeoutMs = connectionAttemptTimeoutMs(config);
|
||||
const timeoutMessage = connectionAttemptTimeoutMessage(timeoutMs);
|
||||
|
|
@ -768,7 +773,7 @@ async function testConnectionWithTimeout(config: ConnectionConfig, runId: number
|
|||
if (runId !== testRunId) return;
|
||||
testResult.value = {
|
||||
ok: false,
|
||||
message: connectionAttemptOriginalErrorMessage(timeoutMessage, errorMessage(error)),
|
||||
message: connectionErrorWithDriverUpdateHint(config, connectionAttemptOriginalErrorMessage(timeoutMessage, errorMessage(error))),
|
||||
};
|
||||
});
|
||||
try {
|
||||
|
|
@ -1554,7 +1559,7 @@ async function testConnection() {
|
|||
testResult.value = { ok: true, message: msg };
|
||||
} catch (e: any) {
|
||||
if (runId !== testRunId) return;
|
||||
const message = mongodbAuthFailureHint(String(e));
|
||||
const message = connectionErrorWithDriverUpdateHint(config, mongodbAuthFailureHint(String(e)));
|
||||
const fallbackMessage = await tryNacosDockerConsoleFallback(config, message, runId);
|
||||
if (runId !== testRunId) return;
|
||||
testResult.value = fallbackMessage ? { ok: true, message: fallbackMessage } : { ok: false, message };
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ export default {
|
|||
systemJavaNotFound: "System Java runtime was not found on PATH. Please install Java or choose a custom Java executable.",
|
||||
customJavaPathEmpty: "Custom Java runtime path is empty. Please choose a Java executable.",
|
||||
agentJavaTooOld: "This driver requires Java 21. Use DBX managed JRE 21 or select a Java 21 executable in Driver Manager.",
|
||||
agentDriverUpdateConnectionHint: "A built-in driver update is available for this connection. The connection failure may be related to an outdated local driver. Update the corresponding driver in Driver Manager, then retry.",
|
||||
jdbcPluginNotInstalled: "JDBC plugin is not installed. Install the optional JDBC plugin to use this connection.",
|
||||
lastError: "Connection error",
|
||||
clearError: "Clear connection error",
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ export default withEnglishFallback({
|
|||
systemJavaNotFound: "未在 PATH 中找到系统 Java 运行环境,请安装 Java 或选择自定义 Java 可执行文件。",
|
||||
customJavaPathEmpty: "自定义 Java 运行环境路径为空,请选择 Java 可执行文件。",
|
||||
agentJavaTooOld: "该驱动需要 Java 21。请在驱动管理器中使用 DBX 托管 JRE 21,或选择 Java 21 可执行文件。",
|
||||
agentDriverUpdateConnectionHint: "当前连接使用的内置驱动有可用更新,连接失败可能与本地驱动版本过旧有关。请在「驱动管理」中更新对应驱动后重试。",
|
||||
jdbcPluginNotInstalled: "JDBC 插件未安装,请先安装 JDBC 插件再使用此连接。",
|
||||
lastError: "连接错误",
|
||||
clearError: "清除连接错误",
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ import { supportsDriverManagement } from "./databaseCapabilities";
|
|||
export interface AgentDriverInstallState {
|
||||
db_type: string;
|
||||
installed: boolean;
|
||||
update_available?: boolean;
|
||||
}
|
||||
|
||||
function agentDriverInstallKey(dbType: DatabaseType | undefined, driverProfile?: string): string | undefined {
|
||||
if (dbType === "oracle") return "oracle";
|
||||
if (dbType === "mongodb") return "mongodb";
|
||||
if (dbType === "dameng") return "dameng";
|
||||
return driverProfile && driverProfile !== dbType ? driverProfile : dbType;
|
||||
}
|
||||
|
||||
|
|
@ -17,3 +19,15 @@ export function showAgentDriverInstallHint(dbType: DatabaseType | undefined, dri
|
|||
const driverKey = agentDriverInstallKey(dbType, driverProfile);
|
||||
return drivers.find((driver) => driver.db_type === driverKey)?.installed !== true;
|
||||
}
|
||||
|
||||
export function hasAgentDriverUpdate(dbType: DatabaseType | undefined, drivers: readonly AgentDriverInstallState[], driverProfile?: string): boolean {
|
||||
if (!supportsDriverManagement(dbType)) return false;
|
||||
const driverKey = agentDriverInstallKey(dbType, driverProfile);
|
||||
return drivers.find((driver) => driver.db_type === driverKey)?.update_available === true;
|
||||
}
|
||||
|
||||
export function appendAgentDriverUpdateHint(message: string, hint: string): string {
|
||||
if (!message.trim()) return hint;
|
||||
if (message.includes(hint)) return message;
|
||||
return `${message}\n\n${hint}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ import { inferMongoCompletionFields, type MongoCompletionField } from "@/lib/mon
|
|||
import { completionSchemasFromTree, completionTablesFromTree } from "@/lib/completionTreeIndex";
|
||||
import { kvRootNodeLabel } from "@/lib/kvRootPresentation";
|
||||
import { REDIS_SCAN_PAGE_SIZE_DEFAULT } from "@/lib/redisKeyPattern";
|
||||
import { appendAgentDriverUpdateHint, hasAgentDriverUpdate, type AgentDriverInstallState } from "@/lib/agentDriverInstallHint";
|
||||
import i18n from "@/i18n";
|
||||
|
||||
const PINNED_TREE_NODES_STORAGE_KEY = "dbx-pinned-tree-nodes";
|
||||
const ACTIVE_CONNECTION_STORAGE_KEY = "dbx-active-connection";
|
||||
|
|
@ -168,6 +170,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
const pinnedTreeNodeIds = ref<Set<string>>(new Set());
|
||||
const connectedIds = ref<Set<string>>(new Set());
|
||||
const lastConnectionHealthCheckAt = ref<Record<string, number>>({});
|
||||
const agentDrivers = ref<AgentDriverInstallState[]>([]);
|
||||
let agentDriversRefreshPromise: Promise<void> | null = null;
|
||||
const loadedTreeNodeChildrenIds = ref<Set<string>>(new Set());
|
||||
const connectionErrors = ref<Record<string, string>>({});
|
||||
const editingConnectionId = ref<string | null>(null);
|
||||
|
|
@ -277,6 +281,44 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
connectionErrors.value[connectionId] = message;
|
||||
}
|
||||
|
||||
function agentDriverUpdateHint(): string {
|
||||
return i18n.global.t("connection.agentDriverUpdateConnectionHint");
|
||||
}
|
||||
|
||||
function connectionErrorWithDriverUpdateHint(config: ConnectionConfig | undefined, message: string): string {
|
||||
if (!config) return message;
|
||||
if (!hasAgentDriverUpdate(config.db_type, agentDrivers.value, config.driver_profile)) return message;
|
||||
return appendAgentDriverUpdateHint(message, agentDriverUpdateHint());
|
||||
}
|
||||
|
||||
function refreshAgentDriversForErrorHint(): Promise<void> {
|
||||
if (agentDriversRefreshPromise) return agentDriversRefreshPromise;
|
||||
agentDriversRefreshPromise = api
|
||||
.listInstalledAgents()
|
||||
.then((drivers) => {
|
||||
agentDrivers.value = drivers;
|
||||
})
|
||||
.catch(() => undefined)
|
||||
.finally(() => {
|
||||
agentDriversRefreshPromise = null;
|
||||
});
|
||||
return agentDriversRefreshPromise;
|
||||
}
|
||||
|
||||
function maybeAppendAgentDriverUpdateHint(connectionId: string, baseMessage: string) {
|
||||
const config = getConfig(connectionId);
|
||||
const message = connectionErrorWithDriverUpdateHint(config, baseMessage);
|
||||
if (message !== baseMessage) {
|
||||
setConnectionError(connectionId, message);
|
||||
return;
|
||||
}
|
||||
void refreshAgentDriversForErrorHint().then(() => {
|
||||
if (connectionErrors.value[connectionId] !== baseMessage) return;
|
||||
const refreshedMessage = connectionErrorWithDriverUpdateHint(config, baseMessage);
|
||||
if (refreshedMessage !== baseMessage) setConnectionError(connectionId, refreshedMessage);
|
||||
});
|
||||
}
|
||||
|
||||
function clearConnectionError(connectionId: string) {
|
||||
if (!connectionErrors.value[connectionId]) return;
|
||||
delete connectionErrors.value[connectionId];
|
||||
|
|
@ -369,6 +411,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
function recordConnectionError(connectionId: string, error: unknown): string {
|
||||
const message = connectionErrorMessage(error);
|
||||
setConnectionError(connectionId, message);
|
||||
maybeAppendAgentDriverUpdateHint(connectionId, message);
|
||||
return message;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { test } from "vitest";
|
||||
import { showAgentDriverInstallHint } from "../../apps/desktop/src/lib/agentDriverInstallHint.ts";
|
||||
import { appendAgentDriverUpdateHint, hasAgentDriverUpdate, showAgentDriverInstallHint } from "../../apps/desktop/src/lib/agentDriverInstallHint.ts";
|
||||
|
||||
test("hides the agent driver install hint when the selected driver is installed", () => {
|
||||
assert.equal(showAgentDriverInstallHint("informix", [{ db_type: "informix", installed: true }]), false);
|
||||
|
|
@ -23,30 +23,9 @@ test("does not show agent driver install hints for built-in database types", ()
|
|||
});
|
||||
|
||||
test("uses the unified Oracle driver for legacy Oracle profiles", () => {
|
||||
assert.equal(
|
||||
showAgentDriverInstallHint(
|
||||
"oracle",
|
||||
[{ db_type: "oracle", installed: false }],
|
||||
"oracle-10g",
|
||||
),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
showAgentDriverInstallHint(
|
||||
"oracle",
|
||||
[{ db_type: "oracle", installed: true }],
|
||||
"oracle",
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
showAgentDriverInstallHint(
|
||||
"oracle",
|
||||
[{ db_type: "oracle", installed: true }],
|
||||
"oracle-legacy",
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(showAgentDriverInstallHint("oracle", [{ db_type: "oracle", installed: false }], "oracle-10g"), true);
|
||||
assert.equal(showAgentDriverInstallHint("oracle", [{ db_type: "oracle", installed: true }], "oracle"), false);
|
||||
assert.equal(showAgentDriverInstallHint("oracle", [{ db_type: "oracle", installed: true }], "oracle-legacy"), false);
|
||||
assert.equal(showAgentDriverInstallHint("oracle", [{ db_type: "oracle", installed: false }], "oracle"), true);
|
||||
});
|
||||
|
||||
|
|
@ -74,3 +53,31 @@ test("uses selected non-Oracle agent driver profiles for install hints", () => {
|
|||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("detects available updates for the selected agent driver", () => {
|
||||
assert.equal(hasAgentDriverUpdate("dameng", [{ db_type: "dameng", installed: true, update_available: true }], "dm"), true);
|
||||
assert.equal(hasAgentDriverUpdate("dameng", [{ db_type: "dameng", installed: true, update_available: false }], "dm"), false);
|
||||
assert.equal(hasAgentDriverUpdate("mysql", [{ db_type: "mysql", installed: true, update_available: true }]), false);
|
||||
});
|
||||
|
||||
test("uses unified Oracle and selected profile keys for update hints", () => {
|
||||
assert.equal(hasAgentDriverUpdate("oracle", [{ db_type: "oracle", installed: true, update_available: true }], "oracle-10g"), true);
|
||||
assert.equal(
|
||||
hasAgentDriverUpdate(
|
||||
"gbase",
|
||||
[
|
||||
{ db_type: "gbase", installed: true, update_available: false },
|
||||
{ db_type: "gbase8s", installed: true, update_available: true },
|
||||
],
|
||||
"gbase8s",
|
||||
),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("appends agent driver update hints once", () => {
|
||||
const hint = "Driver update available.";
|
||||
assert.equal(appendAgentDriverUpdateHint("Original error", hint), "Original error\n\nDriver update available.");
|
||||
assert.equal(appendAgentDriverUpdateHint("Original error\n\nDriver update available.", hint), "Original error\n\nDriver update available.");
|
||||
assert.equal(appendAgentDriverUpdateHint("", hint), hint);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue