feat(web): support driver management

This commit is contained in:
t8y2
2026-05-18 18:16:25 +08:00
parent af16ac219c
commit b01c17e709
13 changed files with 766 additions and 49 deletions
+6 -3
View File
@@ -623,14 +623,16 @@ function handleContextMenu(e: MouseEvent) {
e.preventDefault();
}
function openDriverStoreFromEvent() {
showDriverStore.value = true;
}
onMounted(async () => {
console.log("[STARTUP] onMounted begin");
const mountStart = performance.now();
applyTheme();
window.addEventListener("keydown", handleKeydown, true);
window.addEventListener("dbx-open-driver-store", () => {
showDriverStore.value = true;
});
window.addEventListener("dbx-open-driver-store", openDriverStoreFromEvent);
if (isDesktop) {
document.addEventListener("contextmenu", handleContextMenu);
}
@@ -684,6 +686,7 @@ onUnmounted(() => {
clearInterval(updateCheckTimer);
}
window.removeEventListener("keydown", handleKeydown, true);
window.removeEventListener("dbx-open-driver-store", openDriverStoreFromEvent);
document.removeEventListener("contextmenu", handleContextMenu);
});
</script>
@@ -1,8 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from "vue";
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import type { UnlistenFn } from "@tauri-apps/api/event";
import { useI18n } from "vue-i18n";
import { FolderOpen, Trash2, Download, RotateCcw, Loader2, RefreshCw, Check, Clock3 } from "lucide-vue-next";
import { Button } from "@/components/ui/button";
@@ -17,6 +14,7 @@ import { isTauriRuntime } from "@/lib/tauriRuntime";
import { countAvailableAgentDriverUpdates } from "@/lib/agentDriverUpdateBadge";
import type { JdbcDriverInfo, JdbcPluginStatus } from "@/types/database";
import * as api from "@/lib/api";
import type { AgentDriverInfo, JavaRuntimeConfig } from "@/lib/api";
import {
addDriverInstallQueue,
driverInstallProgressPercent,
@@ -36,25 +34,6 @@ const emit = defineEmits<{
// ──────────── Agent drivers ────────────
interface AgentDriverInfo {
db_type: string;
label: string;
version: string;
size: number;
installed: boolean;
installed_version: string | null;
update_available: boolean;
jre: string;
jre_installed: boolean;
}
type JavaRuntimeMode = "managed" | "system" | "custom";
interface JavaRuntimeConfig {
mode: JavaRuntimeMode;
custom_java_path: string | null;
}
const drivers = ref<AgentDriverInfo[]>([]);
const installing = ref<string | null>(null);
const upgradingAll = ref(false);
@@ -69,7 +48,7 @@ const javaRuntimeConfig = ref<JavaRuntimeConfig>({ mode: "managed", custom_java_
const customJavaPath = ref("");
const savingJavaRuntime = ref(false);
let unlisten: UnlistenFn | null = null;
let unlisten: (() => void) | null = null;
const installedJres = computed(() => {
const jreMap = new Map<string, boolean>();
@@ -138,13 +117,13 @@ function removeQueuedDriverInstall(dbType: string) {
}
async function refreshAgents() {
updateAgentDrivers(await invoke<AgentDriverInfo[]>("list_installed_agents"));
updateAgentDrivers(await api.listInstalledAgents());
}
async function forceRefresh() {
refreshing.value = true;
try {
await invoke("invalidate_agent_registry_cache");
await api.invalidateAgentRegistryCache();
await refreshAgents();
} finally {
refreshing.value = false;
@@ -152,7 +131,7 @@ async function forceRefresh() {
}
async function loadJavaRuntimeConfig() {
const config = await invoke<JavaRuntimeConfig>("get_agent_java_runtime_config");
const config = await api.getAgentJavaRuntimeConfig();
javaRuntimeConfig.value = config;
customJavaPath.value = config.custom_java_path ?? "";
}
@@ -166,11 +145,9 @@ function setJavaRuntimeMode(value: any) {
async function saveJavaRuntimeConfig() {
savingJavaRuntime.value = true;
try {
const config = await invoke<JavaRuntimeConfig>("set_agent_java_runtime_config", {
config: {
mode: javaRuntimeConfig.value.mode,
custom_java_path: javaRuntimeConfig.value.mode === "custom" ? customJavaPath.value.trim() || null : null,
},
const config = await api.setAgentJavaRuntimeConfig({
mode: javaRuntimeConfig.value.mode,
custom_java_path: javaRuntimeConfig.value.mode === "custom" ? customJavaPath.value.trim() || null : null,
});
javaRuntimeConfig.value = config;
customJavaPath.value = config.custom_java_path ?? "";
@@ -208,7 +185,7 @@ async function runDriverInstall(dbType: string) {
installing.value = dbType;
progress.value = null;
try {
await invoke("install_agent", { dbType });
await api.installAgent(dbType);
await refreshAgents();
toast(`${label} 驱动安装成功`);
} catch (e: any) {
@@ -235,7 +212,7 @@ async function upgradeAll() {
queuedDriverInstalls.value = [];
progress.value = null;
try {
const count = await invoke<number>("upgrade_all_agents");
const count = await api.upgradeAllAgents();
await refreshAgents();
toast(`${count} 个驱动升级完成`);
} catch (e: any) {
@@ -252,7 +229,7 @@ async function upgradeAll() {
async function uninstallDriver(dbType: string) {
const label = drivers.value.find((d) => d.db_type === dbType)?.label ?? dbType;
try {
await invoke("uninstall_agent", { dbType });
await api.uninstallAgent(dbType);
await refreshAgents();
toast(`${label} 驱动已卸载`);
} catch (e: any) {
@@ -264,7 +241,7 @@ async function reinstallJre(jreKey: string) {
reinstallingJre.value = jreKey;
progress.value = null;
try {
await invoke("reinstall_jre", { jreKey });
await api.reinstallJre(jreKey);
await refreshAgents();
toast(`JRE ${jreKey} 重新安装成功`);
} catch (e: any) {
@@ -277,7 +254,7 @@ async function reinstallJre(jreKey: string) {
async function uninstallJre(jreKey: string) {
try {
await invoke("uninstall_jre", { jreKey });
await api.uninstallJre(jreKey);
await refreshAgents();
toast(`JRE ${jreKey} 已卸载`);
} catch (e: any) {
@@ -352,7 +329,7 @@ async function installJdbcPluginLocal() {
if (typeof selected !== "string") return;
isInstallingJdbcPlugin.value = true;
try {
jdbcPluginStatus.value = await invoke<JdbcPluginStatus>("install_jdbc_plugin_local", { path: selected });
jdbcPluginStatus.value = await api.installJdbcPluginLocal(selected);
toast(t("settings.jdbcPluginInstallSuccess"));
await loadJdbcDrivers();
} catch (e: any) {
@@ -423,19 +400,18 @@ async function deleteJdbcDriver(path: string) {
// ──────────── Lifecycle ────────────
onMounted(async () => {
updateAgentDrivers(await invoke<AgentDriverInfo[]>("list_installed_agents_local"));
updateAgentDrivers(await api.listInstalledAgentsLocal());
void loadJavaRuntimeConfig();
invoke<AgentDriverInfo[]>("list_installed_agents").then((result) => {
api.listInstalledAgents().then((result) => {
updateAgentDrivers(result);
});
unlisten = await listen<DriverInstallProgress>("agent-install-progress", (event) => {
const payload = event.payload as any;
unlisten = await api.listenAgentInstallProgress((payload) => {
if (payload.step === "done" || payload.step === "all-done") {
progress.value = null;
} else {
progress.value = payload;
progress.value = payload as DriverInstallProgress;
}
if (payload.db_type && payload.total_drivers) {
upgradingCurrent.value = drivers.value.find((d) => d.db_type === payload.db_type)?.label ?? payload.db_type;
@@ -1,6 +1,5 @@
<script setup lang="ts">
import { computed, nextTick, ref, watch } from "vue";
import { invoke } from "@tauri-apps/api/core";
import { uuid } from "@/lib/utils";
import { useI18n } from "vue-i18n";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
@@ -736,10 +735,10 @@ async function loadJdbcDrivers() {
}
async function loadAgentDrivers() {
if (!isDesktop) return;
try {
agentDrivers.value = await invoke<AgentDriverInstallState[]>("list_installed_agents_local");
invoke<AgentDriverInstallState[]>("list_installed_agents")
agentDrivers.value = await api.listInstalledAgentsLocal();
api
.listInstalledAgents()
.then((drivers) => {
agentDrivers.value = drivers;
})
+16
View File
@@ -42,7 +42,19 @@ export const importJdbcDrivers = forward("importJdbcDrivers");
export const deleteJdbcDriver = forward("deleteJdbcDriver");
export const jdbcPluginStatus = forward("jdbcPluginStatus");
export const installJdbcPlugin = forward("installJdbcPlugin");
export const installJdbcPluginLocal = forward("installJdbcPluginLocal");
export const uninstallJdbcPlugin = forward("uninstallJdbcPlugin");
export const listInstalledAgentsLocal = forward("listInstalledAgentsLocal");
export const listInstalledAgents = forward("listInstalledAgents");
export const installAgent = forward("installAgent");
export const upgradeAllAgents = forward("upgradeAllAgents");
export const uninstallAgent = forward("uninstallAgent");
export const getAgentJavaRuntimeConfig = forward("getAgentJavaRuntimeConfig");
export const setAgentJavaRuntimeConfig = forward("setAgentJavaRuntimeConfig");
export const invalidateAgentRegistryCache = forward("invalidateAgentRegistryCache");
export const reinstallJre = forward("reinstallJre");
export const uninstallJre = forward("uninstallJre");
export const listenAgentInstallProgress = forward("listenAgentInstallProgress");
export const loadSavedSqlLibrary = forward("loadSavedSqlLibrary");
export const saveSavedSqlFolder = forward("saveSavedSqlFolder");
export const deleteSavedSqlFolder = forward("deleteSavedSqlFolder");
@@ -157,6 +169,10 @@ export type {
AiStreamChunk,
AiChatMessage,
AiConversation,
AgentDriverInfo,
JavaRuntimeMode,
JavaRuntimeConfig,
DriverInstallProgress,
UpdateInfo,
RedisDatabaseInfo,
RedisKeyInfo,
+62
View File
@@ -20,9 +20,12 @@ import type {
} from "@/types/database";
import type { AiConfig } from "@/stores/settingsStore";
import type {
AgentDriverInfo,
AiCompletionRequest,
AiStreamChunk,
AiConversation,
DriverInstallProgress,
JavaRuntimeConfig,
UpdateInfo,
RedisDatabaseInfo,
RedisValue,
@@ -125,10 +128,69 @@ export async function installJdbcPlugin(): Promise<JdbcPluginStatus> {
return { installed: false, version: null, protocol_version: null, compatible: true, path: "" };
}
export async function installJdbcPluginLocal(_path: string): Promise<JdbcPluginStatus> {
return { installed: false, version: null, protocol_version: null, compatible: true, path: "" };
}
export async function uninstallJdbcPlugin(): Promise<JdbcPluginStatus> {
return { installed: false, version: null, protocol_version: null, compatible: true, path: "" };
}
export async function listInstalledAgentsLocal(): Promise<AgentDriverInfo[]> {
return get("/api/agents/installed-local");
}
export async function listInstalledAgents(): Promise<AgentDriverInfo[]> {
return get("/api/agents/installed");
}
export async function installAgent(dbType: string): Promise<void> {
await post("/api/agents/install", { dbType });
}
export async function upgradeAllAgents(): Promise<number> {
const result: { count: number } = await post("/api/agents/upgrade-all", {});
return result.count;
}
export async function uninstallAgent(dbType: string): Promise<void> {
await post("/api/agents/uninstall", { dbType });
}
export async function getAgentJavaRuntimeConfig(): Promise<JavaRuntimeConfig> {
return get("/api/agents/java-runtime");
}
export async function setAgentJavaRuntimeConfig(config: JavaRuntimeConfig): Promise<JavaRuntimeConfig> {
return post("/api/agents/java-runtime", { config });
}
export async function invalidateAgentRegistryCache(): Promise<void> {
await post("/api/agents/invalidate-registry-cache", {});
}
export async function reinstallJre(jreKey?: string): Promise<void> {
await post("/api/agents/reinstall-jre", { jreKey });
}
export async function uninstallJre(jreKey: string): Promise<void> {
await post("/api/agents/uninstall-jre", { jreKey });
}
export async function listenAgentInstallProgress(
handler: (progress: DriverInstallProgress) => void,
): Promise<() => void> {
const es = new EventSource("/api/agents/progress/global");
es.onmessage = (event) => {
try {
handler(JSON.parse(event.data));
} catch {
/* ignore malformed progress events */
}
};
return () => es.close();
}
export async function loadSavedSqlLibrary(): Promise<SavedSqlLibrary> {
return get("/api/saved-sql");
}
+78
View File
@@ -21,6 +21,34 @@ import type {
} from "@/types/database";
import type { AiConfig } from "@/stores/settingsStore";
export interface AgentDriverInfo {
db_type: string;
label: string;
version: string;
size: number;
installed: boolean;
installed_version: string | null;
update_available: boolean;
jre: string;
jre_installed: boolean;
}
export type JavaRuntimeMode = "managed" | "system" | "custom";
export interface JavaRuntimeConfig {
mode: JavaRuntimeMode;
custom_java_path: string | null;
}
export interface DriverInstallProgress {
step: string;
downloaded?: number;
total?: number;
db_type?: string;
current?: number;
total_drivers?: number;
}
export interface AiMessage {
role: "user" | "assistant" | "system";
content: string;
@@ -304,10 +332,60 @@ export async function installJdbcPlugin(): Promise<JdbcPluginStatus> {
return invoke("install_jdbc_plugin");
}
export async function installJdbcPluginLocal(path: string): Promise<JdbcPluginStatus> {
return invoke("install_jdbc_plugin_local", { path });
}
export async function uninstallJdbcPlugin(): Promise<JdbcPluginStatus> {
return invoke("uninstall_jdbc_plugin");
}
export async function listInstalledAgentsLocal(): Promise<AgentDriverInfo[]> {
return invoke("list_installed_agents_local");
}
export async function listInstalledAgents(): Promise<AgentDriverInfo[]> {
return invoke("list_installed_agents");
}
export async function installAgent(dbType: string): Promise<void> {
return invoke("install_agent", { dbType });
}
export async function upgradeAllAgents(): Promise<number> {
return invoke("upgrade_all_agents");
}
export async function uninstallAgent(dbType: string): Promise<void> {
return invoke("uninstall_agent", { dbType });
}
export async function getAgentJavaRuntimeConfig(): Promise<JavaRuntimeConfig> {
return invoke("get_agent_java_runtime_config");
}
export async function setAgentJavaRuntimeConfig(config: JavaRuntimeConfig): Promise<JavaRuntimeConfig> {
return invoke("set_agent_java_runtime_config", { config });
}
export async function invalidateAgentRegistryCache(): Promise<void> {
return invoke("invalidate_agent_registry_cache");
}
export async function reinstallJre(jreKey?: string): Promise<void> {
return invoke("reinstall_jre", { jreKey });
}
export async function uninstallJre(jreKey: string): Promise<void> {
return invoke("uninstall_jre", { jreKey });
}
export async function listenAgentInstallProgress(
handler: (progress: DriverInstallProgress) => void,
): Promise<UnlistenFn> {
return listen<DriverInstallProgress>("agent-install-progress", (event) => handler(event.payload));
}
export async function loadSavedSqlLibrary(): Promise<SavedSqlLibrary> {
return invoke("load_saved_sql_library");
}