From 51ab706c0ed632579df6fd02e104befe25788b8e Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 18 May 2026 17:46:59 +0800 Subject: [PATCH] feat(drivers): queue agent installs --- .../config/DriverInstallProgressCircle.vue | 35 ++++ .../components/config/DriverStoreDialog.vue | 153 +++++++++++++----- .../src/lib/driverInstallProgressUi.ts | 46 ++++++ .../app-tests/driverInstallProgressUi.test.ts | 58 +++++++ 4 files changed, 254 insertions(+), 38 deletions(-) create mode 100644 apps/desktop/src/components/config/DriverInstallProgressCircle.vue create mode 100644 apps/desktop/src/lib/driverInstallProgressUi.ts create mode 100644 packages/app-tests/driverInstallProgressUi.test.ts diff --git a/apps/desktop/src/components/config/DriverInstallProgressCircle.vue b/apps/desktop/src/components/config/DriverInstallProgressCircle.vue new file mode 100644 index 0000000000..be21107667 --- /dev/null +++ b/apps/desktop/src/components/config/DriverInstallProgressCircle.vue @@ -0,0 +1,35 @@ + + + diff --git a/apps/desktop/src/components/config/DriverStoreDialog.vue b/apps/desktop/src/components/config/DriverStoreDialog.vue index c90e568518..e3ac7c10f2 100644 --- a/apps/desktop/src/components/config/DriverStoreDialog.vue +++ b/apps/desktop/src/components/config/DriverStoreDialog.vue @@ -4,18 +4,27 @@ 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 } from "lucide-vue-next"; +import { FolderOpen, Trash2, Download, RotateCcw, Loader2, RefreshCw, Check, Clock3 } from "lucide-vue-next"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import DriverInstallProgressCircle from "@/components/config/DriverInstallProgressCircle.vue"; import DatabaseIcon from "@/components/icons/DatabaseIcon.vue"; import { useToast } from "@/composables/useToast"; import { isTauriRuntime } from "@/lib/tauriRuntime"; import { countAvailableAgentDriverUpdates } from "@/lib/agentDriverUpdateBadge"; import type { JdbcDriverInfo, JdbcPluginStatus } from "@/types/database"; import * as api from "@/lib/api"; +import { + addDriverInstallQueue, + driverInstallProgressPercent, + isDriverInstallProgressTarget, + removeDriverInstallQueue, + takeNextDriverInstallQueue, + type DriverInstallProgress, +} from "@/lib/driverInstallProgressUi"; const { t } = useI18n(); const { toast } = useToast(); @@ -39,12 +48,6 @@ interface AgentDriverInfo { jre_installed: boolean; } -interface InstallProgress { - step: string; - downloaded?: number; - total?: number; -} - type JavaRuntimeMode = "managed" | "system" | "custom"; interface JavaRuntimeConfig { @@ -58,9 +61,10 @@ const upgradingAll = ref(false); const upgradingCurrent = ref(""); const upgradingIndex = ref(0); const upgradingTotal = ref(0); +const queuedDriverInstalls = ref([]); const reinstallingJre = ref(null); const refreshing = ref(false); -const progress = ref(null); +const progress = ref(null); const javaRuntimeConfig = ref({ mode: "managed", custom_java_path: null }); const customJavaPath = ref(""); const savingJavaRuntime = ref(false); @@ -95,11 +99,7 @@ const progressText = computed(() => { return `${prefix}${label} ${dl} / ${total} (${pct}%)`; }); -const progressPercent = computed(() => { - const p = progress.value; - if (!p || !p.total) return 0; - return Math.round(((p.downloaded ?? 0) / p.total) * 100); -}); +const progressNumber = computed(() => driverInstallProgressPercent(progress.value)); const updatableCount = computed(() => drivers.value.filter((d) => d.update_available).length); @@ -108,6 +108,35 @@ function updateAgentDrivers(nextDrivers: AgentDriverInfo[]) { emit("update-count-change", countAvailableAgentDriverUpdates(nextDrivers)); } +function isDriverProgressActive(dbType: string): boolean { + return isDriverInstallProgressTarget(dbType, { + installing: installing.value, + upgradingAll: upgradingAll.value, + progress: progress.value, + }); +} + +function progressTitle(fallback: string): string { + return progressText.value || fallback; +} + +function isDriverQueued(dbType: string): boolean { + return queuedDriverInstalls.value.includes(dbType); +} + +function canInstallOrUpdateDriver(dbType: string): boolean { + const driver = drivers.value.find((d) => d.db_type === dbType); + return Boolean(driver && (!driver.installed || driver.update_available)); +} + +function queueDriverInstall(dbType: string) { + queuedDriverInstalls.value = addDriverInstallQueue(queuedDriverInstalls.value, dbType, installing.value); +} + +function removeQueuedDriverInstall(dbType: string) { + queuedDriverInstalls.value = removeDriverInstallQueue(queuedDriverInstalls.value, dbType); +} + async function refreshAgents() { updateAgentDrivers(await invoke("list_installed_agents")); } @@ -166,6 +195,15 @@ async function chooseCustomJavaPath() { } async function installDriver(dbType: string) { + if (installing.value !== null || upgradingAll.value) { + queueDriverInstall(dbType); + return; + } + await runDriverInstall(dbType); + await runQueuedDriverInstalls(); +} + +async function runDriverInstall(dbType: string) { const label = drivers.value.find((d) => d.db_type === dbType)?.label ?? dbType; installing.value = dbType; progress.value = null; @@ -181,8 +219,20 @@ async function installDriver(dbType: string) { } } +async function runQueuedDriverInstalls() { + if (installing.value !== null || upgradingAll.value) return; + + const result = takeNextDriverInstallQueue(queuedDriverInstalls.value, canInstallOrUpdateDriver); + queuedDriverInstalls.value = result.queue; + if (!result.next) return; + + await runDriverInstall(result.next); + await runQueuedDriverInstalls(); +} + async function upgradeAll() { upgradingAll.value = true; + queuedDriverInstalls.value = []; progress.value = null; try { const count = await invoke("upgrade_all_agents"); @@ -380,7 +430,7 @@ onMounted(async () => { updateAgentDrivers(result); }); - unlisten = await listen("agent-install-progress", (event) => { + unlisten = await listen("agent-install-progress", (event) => { const payload = event.payload as any; if (payload.step === "done" || payload.step === "all-done") { progress.value = null; @@ -476,27 +526,34 @@ onUnmounted(() => {
未安装 +
- -
-
{{ progressText }}
-
-
-
-
-
加载中...
@@ -587,33 +633,64 @@ onUnmounted(() => {
+ +