feat(jdbc): install drivers from Maven bundles
This commit is contained in:
1 parent
f969db571c
commit
70f7b464b7
19 files changed
+1039
-51
No files matched your search
@@ -12,7 +12,7 @@ const props = defineProps<{
|
||||
<circle class="text-green-600 transition-[stroke-dashoffset] duration-200" cx="16" cy="16" r="13" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" pathLength="100" stroke-dasharray="100" :stroke-dashoffset="100 - (props.percent ?? 0)" />
|
||||
</svg>
|
||||
<span class="relative z-10 font-mono text-[10px] font-semibold leading-none text-green-700 tabular-nums">
|
||||
{{ props.percent ?? "..." }}
|
||||
{{ props.percent ?? 0 }}
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
@@ -5,6 +5,7 @@ import { Activity, ExternalLink, Cpu, FolderOpen, MemoryStick, Search, Square, T
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
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";
|
||||
@@ -12,7 +13,7 @@ import DatabaseIcon from "@/components/icons/DatabaseIcon.vue";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { isTauriRuntime } from "@/lib/tauriRuntime";
|
||||
import { countAvailableDriverUpdates } from "@/lib/agentDriverUpdateBadge";
|
||||
import type { JdbcDriverInfo, JdbcPluginStatus } from "@/types/database";
|
||||
import type { JdbcDriverInfo, JdbcMavenBundleInfo, JdbcPluginStatus } from "@/types/database";
|
||||
import * as api from "@/lib/api";
|
||||
import type { AgentDriverInfo, DriverRuntimeInfo, DriverRuntimeSummary, DriverStoreUsage, JavaRuntimeConfig } from "@/lib/api";
|
||||
import { formatRuntimeBytes, formatRuntimeCpu, formatRuntimeUptime, runtimeHealthClass, runtimeStatusClass, runtimeStatusDotClass } from "@/lib/driverRuntimePresentation";
|
||||
@@ -63,6 +64,7 @@ const DRIVER_RUNTIME_POLL_MS = 5000;
|
||||
const OFFLINE_DRIVER_DOWNLOAD_URL = "https://dbxio.com/cn/drivers";
|
||||
|
||||
let unlisten: (() => void) | null = null;
|
||||
const lastProgressPercent = ref<number | null>(null);
|
||||
|
||||
const installedJres = computed(() => {
|
||||
const jreMap = new Map<string, boolean>();
|
||||
@@ -78,16 +80,28 @@ const progressText = computed(() => {
|
||||
const p = progress.value;
|
||||
if (!p) return "";
|
||||
if (p.step === "jre-extract") return t("driverStore.progressJreExtract");
|
||||
const label = p.step === "jre" ? t("driverStore.progressDownloadJre") : t("driverStore.progressDownloadDriver");
|
||||
if (p.step === "jdbc-plugin-extract") return t("driverStore.progressJdbcPluginExtract");
|
||||
const label = p.step === "jre" ? t("driverStore.progressDownloadJre") : p.step === "jdbc-plugin" ? t("driverStore.progressDownloadJdbcPlugin") : t("driverStore.progressDownloadDriver");
|
||||
if (!p.total) return `${label}...`;
|
||||
const pct = Math.round(((p.downloaded ?? 0) / p.total) * 100);
|
||||
const dl = formatSize(p.downloaded ?? 0);
|
||||
const total = formatSize(p.total);
|
||||
const prefix = upgradingAll.value && upgradingCurrent.value ? `[${upgradingIndex.value}/${upgradingTotal.value}] ${upgradingCurrent.value} — ` : "";
|
||||
const prefix = upgradingAll.value && upgradingCurrent.value ? `[${upgradingIndex.value}/${upgradingTotal.value}] ${upgradingCurrent.value} - ` : "";
|
||||
return `${prefix}${label} ${dl} / ${total} (${pct}%)`;
|
||||
});
|
||||
|
||||
const progressNumber = computed(() => driverInstallProgressPercent(progress.value));
|
||||
const progressNumber = computed(() => {
|
||||
const next = driverInstallProgressPercent(progress.value);
|
||||
if (next !== null) {
|
||||
lastProgressPercent.value = next;
|
||||
}
|
||||
return next ?? lastProgressPercent.value;
|
||||
});
|
||||
|
||||
function resetInstallProgress() {
|
||||
progress.value = null;
|
||||
lastProgressPercent.value = null;
|
||||
}
|
||||
|
||||
const updatableCount = computed(() => (props.updateNotificationsEnabled ? drivers.value.filter((d) => d.update_available).length : 0));
|
||||
const usageSummary = computed(() => {
|
||||
@@ -231,7 +245,7 @@ async function installDriver(dbType: string) {
|
||||
async function runDriverInstall(dbType: string) {
|
||||
const label = drivers.value.find((d) => d.db_type === dbType)?.label ?? dbType;
|
||||
installing.value = dbType;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
try {
|
||||
const blockers = await api.checkAgentUpdateBlockers([dbType]);
|
||||
if (blockers.length > 0) {
|
||||
@@ -245,7 +259,7 @@ async function runDriverInstall(dbType: string) {
|
||||
toast(t("driverStore.driverInstallFailed", { label, error: e }));
|
||||
} finally {
|
||||
installing.value = null;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +277,7 @@ async function runQueuedDriverInstalls() {
|
||||
async function upgradeAll() {
|
||||
upgradingAll.value = true;
|
||||
queuedDriverInstalls.value = [];
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
try {
|
||||
const updatableDbTypes = drivers.value.filter((driver) => driver.update_available).map((driver) => driver.db_type);
|
||||
const blockers = await api.checkAgentUpdateBlockers(updatableDbTypes);
|
||||
@@ -286,7 +300,7 @@ async function upgradeAll() {
|
||||
upgradingCurrent.value = "";
|
||||
upgradingIndex.value = 0;
|
||||
upgradingTotal.value = 0;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +371,7 @@ async function importOfflineZip() {
|
||||
}
|
||||
if (!selected) return;
|
||||
importingZip.value = true;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
try {
|
||||
const count = await api.importAgentsFromZip(selected);
|
||||
await refreshAgents();
|
||||
@@ -366,7 +380,7 @@ async function importOfflineZip() {
|
||||
toast(t("driverStore.offlineImportFailed", { error: e }));
|
||||
} finally {
|
||||
importingZip.value = false;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +416,7 @@ async function importDriverJar(dbType: string) {
|
||||
|
||||
async function reinstallJre(jreKey: string) {
|
||||
reinstallingJre.value = jreKey;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
try {
|
||||
await api.reinstallJre(jreKey);
|
||||
await refreshAgents();
|
||||
@@ -411,7 +425,7 @@ async function reinstallJre(jreKey: string) {
|
||||
toast(t("driverStore.jreReinstallFailed", { jre: jreKey, error: e }));
|
||||
} finally {
|
||||
reinstallingJre.value = null;
|
||||
progress.value = null;
|
||||
resetInstallProgress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,12 +448,45 @@ function formatSize(bytes: number): string {
|
||||
// ──────────── JDBC drivers ────────────
|
||||
|
||||
const jdbcDrivers = ref<JdbcDriverInfo[]>([]);
|
||||
const jdbcMavenBundles = ref<JdbcMavenBundleInfo[]>([]);
|
||||
const jdbcDriverSearch = ref("");
|
||||
const isLoadingJdbcDrivers = ref(false);
|
||||
const jdbcPluginStatus = ref<JdbcPluginStatus | null>(null);
|
||||
const isInstallingJdbcPlugin = ref(false);
|
||||
const isUninstallingJdbcPlugin = ref(false);
|
||||
const jdbcDriverPathInput = ref("");
|
||||
const jdbcMavenCoordinateInput = ref("");
|
||||
const jdbcMavenRepository = ref("https://repo.maven.apache.org/maven2/");
|
||||
const customJdbcMavenRepository = ref("");
|
||||
const isInstallingJdbcMavenDriver = ref(false);
|
||||
|
||||
const jdbcMavenRepositoryOptions = [
|
||||
{ label: "Maven Central", value: "https://repo.maven.apache.org/maven2/" },
|
||||
{ label: "Aliyun", value: "https://maven.aliyun.com/repository/public" },
|
||||
{ label: "Huawei Cloud", value: "https://repo.huaweicloud.com/repository/maven" },
|
||||
{ label: "Tencent Cloud", value: "https://mirrors.cloud.tencent.com/nexus/repository/maven-public" },
|
||||
{ label: "Custom", value: "custom" },
|
||||
];
|
||||
|
||||
type JdbcDriverListItem =
|
||||
| {
|
||||
kind: "manual";
|
||||
id: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
source: string;
|
||||
size: number;
|
||||
driver: JdbcDriverInfo;
|
||||
}
|
||||
| {
|
||||
kind: "maven";
|
||||
id: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
source: string;
|
||||
size: number;
|
||||
bundle: JdbcMavenBundleInfo;
|
||||
};
|
||||
|
||||
const filteredAgentDrivers = computed(() => {
|
||||
const query = agentDriverSearch.value.trim().toLowerCase();
|
||||
@@ -447,10 +494,34 @@ const filteredAgentDrivers = computed(() => {
|
||||
return drivers.value.filter((driver) => [driver.label, driver.db_type, driver.version, driver.installed_version, driver.jre].filter(Boolean).join(" ").toLowerCase().includes(query));
|
||||
});
|
||||
|
||||
const jdbcDriverListItems = computed<JdbcDriverListItem[]>(() => {
|
||||
const bundleItems = jdbcMavenBundles.value.map((bundle) => ({
|
||||
kind: "maven" as const,
|
||||
id: `maven:${bundle.id}`,
|
||||
title: bundle.coordinate,
|
||||
subtitle: `${bundle.artifacts.length} JARs - ${bundle.repositories.join(", ")}`,
|
||||
source: t("driverStore.jdbcSourceMaven"),
|
||||
size: bundle.artifacts.reduce((total, artifact) => total + Number(artifact.size || 0), 0),
|
||||
bundle,
|
||||
}));
|
||||
const manualItems = jdbcDrivers.value
|
||||
.filter((driver) => !driver.bundle_id)
|
||||
.map((driver) => ({
|
||||
kind: "manual" as const,
|
||||
id: `manual:${driver.path}`,
|
||||
title: driver.name,
|
||||
subtitle: driver.path,
|
||||
source: t("driverStore.jdbcSourceManual"),
|
||||
size: driver.size,
|
||||
driver,
|
||||
}));
|
||||
return [...bundleItems, ...manualItems].sort((a, b) => a.title.localeCompare(b.title));
|
||||
});
|
||||
|
||||
const filteredJdbcDrivers = computed(() => {
|
||||
const query = jdbcDriverSearch.value.trim().toLowerCase();
|
||||
if (!query) return jdbcDrivers.value;
|
||||
return jdbcDrivers.value.filter((driver) => [driver.name, driver.path, String(driver.size)].join(" ").toLowerCase().includes(query));
|
||||
if (!query) return jdbcDriverListItems.value;
|
||||
return jdbcDriverListItems.value.filter((item) => [item.title, item.subtitle, String(item.size)].join(" ").toLowerCase().includes(query));
|
||||
});
|
||||
|
||||
function formatBytes(bytes: number) {
|
||||
@@ -568,7 +639,9 @@ function jreUsageLabel(key: string) {
|
||||
async function loadJdbcDrivers() {
|
||||
isLoadingJdbcDrivers.value = true;
|
||||
try {
|
||||
jdbcDrivers.value = await api.listJdbcDrivers();
|
||||
const [drivers, bundles] = await Promise.all([api.listJdbcDrivers(), api.listJdbcMavenBundles()]);
|
||||
jdbcDrivers.value = drivers;
|
||||
jdbcMavenBundles.value = bundles;
|
||||
} catch (e: any) {
|
||||
toast(String(e?.message || e), 5000);
|
||||
} finally {
|
||||
@@ -597,6 +670,7 @@ async function loadJdbcPluginStatus() {
|
||||
async function installJdbcPlugin() {
|
||||
if (isInstallingJdbcPlugin.value) return;
|
||||
isInstallingJdbcPlugin.value = true;
|
||||
resetInstallProgress();
|
||||
try {
|
||||
jdbcPluginStatus.value = await api.installJdbcPlugin();
|
||||
emitDriverUpdateCount();
|
||||
@@ -606,6 +680,7 @@ async function installJdbcPlugin() {
|
||||
toast(String(e?.message || e), 5000);
|
||||
} finally {
|
||||
isInstallingJdbcPlugin.value = false;
|
||||
resetInstallProgress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,6 +772,24 @@ async function importJdbcDriverPathInput() {
|
||||
await importJdbcDriverPaths(paths);
|
||||
}
|
||||
|
||||
async function installJdbcMavenDriver() {
|
||||
const coordinate = jdbcMavenCoordinateInput.value.trim();
|
||||
const repository = jdbcMavenRepository.value === "custom" ? customJdbcMavenRepository.value.trim() : jdbcMavenRepository.value;
|
||||
if (!coordinate || !repository || isInstallingJdbcMavenDriver.value) return;
|
||||
isInstallingJdbcMavenDriver.value = true;
|
||||
try {
|
||||
jdbcDrivers.value = await api.installJdbcDriverFromMaven(coordinate, [repository]);
|
||||
jdbcMavenBundles.value = await api.listJdbcMavenBundles();
|
||||
jdbcMavenCoordinateInput.value = "";
|
||||
void loadDriverStoreUsage();
|
||||
toast(t("driverStore.jdbcMavenInstallSuccess"));
|
||||
} catch (e: any) {
|
||||
toast(String(e?.message || e), 8000);
|
||||
} finally {
|
||||
isInstallingJdbcMavenDriver.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteJdbcDriver(path: string) {
|
||||
try {
|
||||
jdbcDrivers.value = await api.deleteJdbcDriver(path);
|
||||
@@ -707,6 +800,17 @@ async function deleteJdbcDriver(path: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteJdbcMavenBundle(bundleId: string) {
|
||||
try {
|
||||
jdbcDrivers.value = await api.deleteJdbcMavenBundle(bundleId);
|
||||
jdbcMavenBundles.value = await api.listJdbcMavenBundles();
|
||||
void loadDriverStoreUsage();
|
||||
toast(t("settings.jdbcDeleteSuccess"));
|
||||
} catch (e: any) {
|
||||
toast(String(e?.message || e), 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────── Lifecycle ────────────
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -961,6 +1065,7 @@ watch(driverStoreTab, (tab) => {
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center gap-3">
|
||||
<DriverInstallProgressCircle v-if="isInstallingJdbcPlugin" :percent="progressNumber" :title="progressTitle(t('driverStore.progressDownloadJdbcPlugin'))" />
|
||||
<span v-if="jdbcPluginStatus?.installed" class="text-xs" :class="jdbcPluginStatus.compatible ? 'text-green-600' : 'text-destructive'">
|
||||
{{
|
||||
jdbcPluginStatus.compatible
|
||||
@@ -1007,26 +1112,50 @@ watch(driverStoreTab, (tab) => {
|
||||
{{ t("settings.jdbcImport") }}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="grid gap-2 md:grid-cols-[minmax(0,1fr)_180px_auto]">
|
||||
<Input v-model="jdbcMavenCoordinateInput" class="h-8 text-xs" :placeholder="t('driverStore.jdbcMavenCoordinatePlaceholder')" @keydown.enter.prevent="installJdbcMavenDriver" />
|
||||
<Select v-model="jdbcMavenRepository">
|
||||
<SelectTrigger class="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-for="repo in jdbcMavenRepositoryOptions" :key="repo.value" :value="repo.value">
|
||||
{{ repo.label }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button class="h-8 shrink-0 rounded-full" :disabled="!jdbcMavenCoordinateInput.trim() || isInstallingJdbcMavenDriver || (jdbcMavenRepository === 'custom' && !customJdbcMavenRepository.trim())" @click="installJdbcMavenDriver">
|
||||
<Loader2 v-if="isInstallingJdbcMavenDriver" class="h-4 w-4 animate-spin" />
|
||||
<Download v-else class="h-4 w-4" />
|
||||
{{ t("driverStore.jdbcMavenInstall") }}
|
||||
</Button>
|
||||
</div>
|
||||
<Input v-if="jdbcMavenRepository === 'custom'" v-model="customJdbcMavenRepository" class="h-8 text-xs" placeholder="https://repo.example.com/repository/maven-public" @keydown.enter.prevent="installJdbcMavenDriver" />
|
||||
</div>
|
||||
|
||||
<div class="rounded-md border">
|
||||
<div v-if="isLoadingJdbcDrivers" class="p-4 text-sm text-muted-foreground">
|
||||
{{ t("common.loading") }}
|
||||
</div>
|
||||
<div v-else-if="jdbcDrivers.length === 0" class="p-4 text-sm text-muted-foreground">
|
||||
<div v-else-if="jdbcDriverListItems.length === 0" class="p-4 text-sm text-muted-foreground">
|
||||
{{ t("settings.jdbcNoDrivers") }}
|
||||
</div>
|
||||
<div v-else-if="filteredJdbcDrivers.length === 0" class="p-4 text-sm text-muted-foreground">
|
||||
{{ t("driverStore.noMatchingDrivers") }}
|
||||
</div>
|
||||
<div v-else class="divide-y">
|
||||
<div v-for="driver in filteredJdbcDrivers" :key="driver.path" class="flex items-center gap-3 p-3">
|
||||
<div v-for="item in filteredJdbcDrivers" :key="item.id" class="flex items-center gap-3 p-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="truncate text-sm font-medium">{{ driver.name }}</div>
|
||||
<div class="truncate text-xs text-muted-foreground">{{ driver.path }}</div>
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<div class="truncate text-sm font-medium">{{ item.title }}</div>
|
||||
<Badge variant="outline" class="h-5 shrink-0 rounded-full px-2 text-[10px] font-medium">
|
||||
{{ item.source }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="truncate text-xs text-muted-foreground">{{ item.subtitle }}</div>
|
||||
</div>
|
||||
<div class="shrink-0 text-xs text-muted-foreground">{{ formatBytes(driver.size) }}</div>
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8 shrink-0 rounded-full" @click="deleteJdbcDriver(driver.path)">
|
||||
<div class="shrink-0 text-xs text-muted-foreground">{{ formatBytes(item.size) }}</div>
|
||||
<Button variant="ghost" size="icon" class="h-8 w-8 shrink-0 rounded-full" @click="item.kind === 'maven' ? deleteJdbcMavenBundle(item.bundle.id) : deleteJdbcDriver(item.driver.path)">
|
||||
<Trash2 class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import type { ConnectionConfig, DatabaseType, JdbcDriverInfo, ProxyTunnelConfig, SshTunnelConfig, TransportLayerConfig } from "@/types/database";
|
||||
import type { ConnectionConfig, DatabaseType, JdbcDriverInfo, JdbcMavenBundleInfo, ProxyTunnelConfig, SshTunnelConfig, TransportLayerConfig } from "@/types/database";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
@@ -33,6 +33,11 @@ type DbCategory = { key: string; title: string; options: DbOption[] };
|
||||
type DialogStep = "select" | "config";
|
||||
type DbPickerView = "icon" | "list";
|
||||
type ConfigTab = "connection" | "advanced" | "tls" | "transport";
|
||||
type JdbcDriverSelectItem = {
|
||||
id: string;
|
||||
label: string;
|
||||
paths: string[];
|
||||
};
|
||||
|
||||
type LegacyTransportFields = {
|
||||
ssh_enabled?: boolean;
|
||||
@@ -246,6 +251,7 @@ const customDriverName = ref("");
|
||||
const mongoUseUrl = ref(false);
|
||||
const jdbcDriverPathsInput = ref("");
|
||||
const jdbcDrivers = ref<JdbcDriverInfo[]>([]);
|
||||
const jdbcMavenBundles = ref<JdbcMavenBundleInfo[]>([]);
|
||||
const agentDrivers = ref<AgentDriverInstallState[]>([]);
|
||||
const selectedJdbcDriverPath = ref("");
|
||||
const connectionUrlInput = ref("");
|
||||
@@ -270,6 +276,24 @@ const isPresetColor = (color: string | undefined) => colorOptions.some((c) => c.
|
||||
const customColorInput = ref("");
|
||||
const customColorOpen = ref(false);
|
||||
|
||||
const jdbcDriverSelectItems = computed<JdbcDriverSelectItem[]>(() => {
|
||||
const bundles = jdbcMavenBundles.value.map((bundle) => ({
|
||||
id: `maven:${bundle.id}`,
|
||||
label: bundle.coordinate,
|
||||
paths: bundle.artifacts.map((artifact) => artifact.path),
|
||||
}));
|
||||
const manual = jdbcDrivers.value
|
||||
.filter((driver) => !driver.bundle_id)
|
||||
.map((driver) => ({
|
||||
id: `manual:${driver.path}`,
|
||||
label: driver.name,
|
||||
paths: [driver.path],
|
||||
}));
|
||||
return [...bundles, ...manual].sort((left, right) => left.label.localeCompare(right.label));
|
||||
});
|
||||
|
||||
const jdbcDriverSelectItemById = computed(() => new Map(jdbcDriverSelectItems.value.map((item) => [item.id, item])));
|
||||
|
||||
function applyCustomColor(value: string) {
|
||||
form.value.color = value;
|
||||
customColorInput.value = value;
|
||||
@@ -1939,9 +1963,12 @@ async function browseJdbcDriverPaths() {
|
||||
async function loadJdbcDrivers() {
|
||||
if (!isDesktop) return;
|
||||
try {
|
||||
jdbcDrivers.value = await api.listJdbcDrivers();
|
||||
const [drivers, bundles] = await Promise.all([api.listJdbcDrivers(), api.listJdbcMavenBundles()]);
|
||||
jdbcDrivers.value = drivers;
|
||||
jdbcMavenBundles.value = bundles;
|
||||
} catch {
|
||||
jdbcDrivers.value = [];
|
||||
jdbcMavenBundles.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1962,18 +1989,20 @@ async function loadAgentDrivers() {
|
||||
}
|
||||
}
|
||||
|
||||
function addJdbcDriverPath(path: string) {
|
||||
function addJdbcDriverPaths(paths: string[]) {
|
||||
const existing = jdbcDriverPathsInput.value
|
||||
.split(/\r?\n/)
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean);
|
||||
jdbcDriverPathsInput.value = Array.from(new Set([...existing, path])).join("\n");
|
||||
jdbcDriverPathsInput.value = Array.from(new Set([...existing, ...paths])).join("\n");
|
||||
}
|
||||
|
||||
function onJdbcDriverSelect(path: any) {
|
||||
if (typeof path !== "string" || !path) return;
|
||||
selectedJdbcDriverPath.value = path;
|
||||
addJdbcDriverPath(path);
|
||||
function onJdbcDriverSelect(id: any) {
|
||||
if (typeof id !== "string" || !id) return;
|
||||
const item = jdbcDriverSelectItemById.value.get(id);
|
||||
if (!item) return;
|
||||
selectedJdbcDriverPath.value = id;
|
||||
addJdbcDriverPaths(item.paths);
|
||||
}
|
||||
|
||||
function openExternalUrl(url: string) {
|
||||
@@ -2207,13 +2236,13 @@ function openExternalUrl(url: string) {
|
||||
<div class="grid grid-cols-4 items-start gap-4">
|
||||
<Label class="text-right mt-2">{{ t("connection.jdbcDriverPaths") }}</Label>
|
||||
<div class="col-span-3 space-y-2">
|
||||
<Select v-if="jdbcDrivers.length > 0" :model-value="selectedJdbcDriverPath" @update:model-value="onJdbcDriverSelect">
|
||||
<Select v-if="jdbcDriverSelectItems.length > 0" :model-value="selectedJdbcDriverPath" @update:model-value="onJdbcDriverSelect">
|
||||
<SelectTrigger>
|
||||
<SelectValue :placeholder="t('connection.jdbcDriverSelectPlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-for="driver in jdbcDrivers" :key="driver.path" :value="driver.path">
|
||||
{{ driver.name }}
|
||||
<SelectItem v-for="driver in jdbcDriverSelectItems" :key="driver.id" :value="driver.id">
|
||||
{{ driver.label }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
Reference in new issue
Block a user