feat(jdbc): add dedicated connection entry
This commit is contained in:
12 files changed
+76
-11
No files matched your search
@@ -135,6 +135,7 @@ const settingsInitialSection = ref<string | undefined>(undefined);
|
|||||||
const showQueryEditorDdlDialog = ref(false);
|
const showQueryEditorDdlDialog = ref(false);
|
||||||
const driverStoreTabOpen = ref(false);
|
const driverStoreTabOpen = ref(false);
|
||||||
const driverStoreActive = ref(false);
|
const driverStoreActive = ref(false);
|
||||||
|
const driverStoreActiveTab = ref<"agent" | "jdbc" | "storage" | "runtime">("agent");
|
||||||
const settingsReturnSurface = ref<"query" | "driverStore" | "welcome">("welcome");
|
const settingsReturnSurface = ref<"query" | "driverStore" | "welcome">("welcome");
|
||||||
const showDriverStore = computed(() => driverStoreTabOpen.value && driverStoreActive.value);
|
const showDriverStore = computed(() => driverStoreTabOpen.value && driverStoreActive.value);
|
||||||
const showSettingsPage = computed(() => settingsPageTabOpen.value && settingsStore.settingsPageActive);
|
const showSettingsPage = computed(() => settingsPageTabOpen.value && settingsStore.settingsPageActive);
|
||||||
@@ -316,7 +317,8 @@ function closeSettingsPage() {
|
|||||||
driverStoreActive.value = false;
|
driverStoreActive.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openDriverStorePage() {
|
function openDriverStorePage(tab?: "agent" | "jdbc" | "storage" | "runtime") {
|
||||||
|
if (tab) driverStoreActiveTab.value = tab;
|
||||||
driverStoreTabOpen.value = true;
|
driverStoreTabOpen.value = true;
|
||||||
driverStoreActive.value = true;
|
driverStoreActive.value = true;
|
||||||
settingsStore.settingsPageActive = false;
|
settingsStore.settingsPageActive = false;
|
||||||
@@ -325,6 +327,7 @@ function openDriverStorePage() {
|
|||||||
function closeDriverStorePage() {
|
function closeDriverStorePage() {
|
||||||
driverStoreTabOpen.value = false;
|
driverStoreTabOpen.value = false;
|
||||||
driverStoreActive.value = false;
|
driverStoreActive.value = false;
|
||||||
|
driverStoreActiveTab.value = "agent";
|
||||||
}
|
}
|
||||||
const toolbarAgentDriverUpdateCount = computed(() => (updateNotificationsEnabled.value ? agentDriverUpdateCount.value : 0));
|
const toolbarAgentDriverUpdateCount = computed(() => (updateNotificationsEnabled.value ? agentDriverUpdateCount.value : 0));
|
||||||
const toolbarHasUpdateAvailable = computed(() => updateNotificationsEnabled.value && hasUpdateAvailable.value);
|
const toolbarHasUpdateAvailable = computed(() => updateNotificationsEnabled.value && hasUpdateAvailable.value);
|
||||||
@@ -1898,7 +1901,7 @@ onUnmounted(() => {
|
|||||||
@discard-all-tab-close="handleDiscardAllPendingTabClose"
|
@discard-all-tab-close="handleDiscardAllPendingTabClose"
|
||||||
@cancel-tab-close="cancelPendingAppClose"
|
@cancel-tab-close="cancelPendingAppClose"
|
||||||
/>
|
/>
|
||||||
<DriverStorePage v-if="driverStoreTabOpen" v-show="driverStoreActive" class="flex-1 min-h-0" :update-notifications-enabled="updateNotificationsEnabled" @update-count-change="updateAgentDriverUpdateCount" />
|
<DriverStorePage v-if="driverStoreTabOpen" v-show="driverStoreActive" v-model:active-tab="driverStoreActiveTab" class="flex-1 min-h-0" :update-notifications-enabled="updateNotificationsEnabled" @update-count-change="updateAgentDriverUpdateCount" />
|
||||||
<EditorSettingsPage
|
<EditorSettingsPage
|
||||||
v-if="settingsPageTabOpen"
|
v-if="settingsPageTabOpen"
|
||||||
v-show="settingsStore.settingsPageActive"
|
v-show="settingsStore.settingsPageActive"
|
||||||
@@ -2104,7 +2107,7 @@ onUnmounted(() => {
|
|||||||
"
|
"
|
||||||
@open-driver-store="
|
@open-driver-store="
|
||||||
setConnectionDialogOpen(false);
|
setConnectionDialogOpen(false);
|
||||||
openDriverStorePage();
|
openDriverStorePage($event);
|
||||||
"
|
"
|
||||||
@open-tunnel-profile-settings="
|
@open-tunnel-profile-settings="
|
||||||
setConnectionDialogOpen(false);
|
setConnectionDialogOpen(false);
|
||||||
|
|||||||
@@ -28,17 +28,23 @@ const isWeb = !isTauriRuntime();
|
|||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
updateNotificationsEnabled?: boolean;
|
updateNotificationsEnabled?: boolean;
|
||||||
|
activeTab?: "agent" | "jdbc" | "storage" | "runtime";
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
updateNotificationsEnabled: true,
|
updateNotificationsEnabled: true,
|
||||||
|
activeTab: "agent",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
"update-count-change": [count: number];
|
"update-count-change": [count: number];
|
||||||
|
"update:activeTab": [tab: "agent" | "jdbc" | "storage" | "runtime"];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const driverStoreTab = ref("agent");
|
const driverStoreTab = computed({
|
||||||
|
get: () => props.activeTab,
|
||||||
|
set: (tab: "agent" | "jdbc" | "storage" | "runtime") => emit("update:activeTab", tab),
|
||||||
|
});
|
||||||
|
|
||||||
// ──────────── Driver store path ────────────
|
// ──────────── Driver store path ────────────
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ const emit = defineEmits<{
|
|||||||
connectStarted: [name: string];
|
connectStarted: [name: string];
|
||||||
connectSucceeded: [name: string];
|
connectSucceeded: [name: string];
|
||||||
connectFailed: [message: string];
|
connectFailed: [message: string];
|
||||||
openDriverStore: [];
|
openDriverStore: [tab?: "jdbc"];
|
||||||
openTunnelProfileSettings: [];
|
openTunnelProfileSettings: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
@@ -1820,7 +1820,6 @@ const dbOptions: DbOption[] = [
|
|||||||
{ value: "nacos", label: "Nacos" },
|
{ value: "nacos", label: "Nacos" },
|
||||||
{ value: "influxdb", label: "InfluxDB" },
|
{ value: "influxdb", label: "InfluxDB" },
|
||||||
{ value: "iris", label: "IRIS" },
|
{ value: "iris", label: "IRIS" },
|
||||||
{ value: "jdbc", label: "JDBC" },
|
|
||||||
{ value: "manticoresearch", label: "Manticore Search" },
|
{ value: "manticoresearch", label: "Manticore Search" },
|
||||||
{ value: "custom_mysql", label: "Custom (MySQL)" },
|
{ value: "custom_mysql", label: "Custom (MySQL)" },
|
||||||
{ value: "custom_postgres", label: "Custom (PostgreSQL)" },
|
{ value: "custom_postgres", label: "Custom (PostgreSQL)" },
|
||||||
@@ -3833,7 +3832,7 @@ function openExternalUrl(url: string) {
|
|||||||
|
|
||||||
<template v-if="dialogStep === 'select'">
|
<template v-if="dialogStep === 'select'">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-end">
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div class="flex shrink-0 rounded-lg border bg-muted/40 p-0.5">
|
<div class="flex shrink-0 rounded-lg border bg-muted/40 p-0.5">
|
||||||
<Button type="button" size="icon-sm" :variant="dbPickerView === 'icon' ? 'secondary' : 'ghost'" :title="t('connection.iconView')" :aria-label="t('connection.iconView')" @click="dbPickerView = 'icon'">
|
<Button type="button" size="icon-sm" :variant="dbPickerView === 'icon' ? 'secondary' : 'ghost'" :title="t('connection.iconView')" :aria-label="t('connection.iconView')" @click="dbPickerView = 'icon'">
|
||||||
@@ -3848,6 +3847,10 @@ function openExternalUrl(url: string) {
|
|||||||
<Input v-model="dbSearchQuery" class="h-9 pl-8" :placeholder="t('connection.searchDatabasePlaceholder')" />
|
<Input v-model="dbSearchQuery" class="h-9 pl-8" :placeholder="t('connection.searchDatabasePlaceholder')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Button data-jdbc-connection-entry type="button" variant="outline" class="h-9 shrink-0 gap-2" @click="goToConnectionStep('jdbc')">
|
||||||
|
<DatabaseIcon db-type="jdbc" class="h-4 w-4" />
|
||||||
|
{{ t("connection.jdbcConnection") }}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-h-[58vh] space-y-5 overflow-y-auto pr-2">
|
<div class="max-h-[58vh] space-y-5 overflow-y-auto pr-2">
|
||||||
@@ -4132,7 +4135,7 @@ function openExternalUrl(url: string) {
|
|||||||
{{ t("connection.jdbcPluginHint") }}
|
{{ t("connection.jdbcPluginHint") }}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<Button type="button" variant="outline" size="sm" @click="emit('openDriverStore')">
|
<Button type="button" variant="outline" size="sm" @click="emit('openDriverStore', 'jdbc')">
|
||||||
<FolderOpen class="h-3.5 w-3.5" />
|
<FolderOpen class="h-3.5 w-3.5" />
|
||||||
{{ t("toolbar.driverManager") }}
|
{{ t("toolbar.driverManager") }}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -5057,7 +5060,7 @@ function openExternalUrl(url: string) {
|
|||||||
{{ t("connection.jdbcPluginHint") }}
|
{{ t("connection.jdbcPluginHint") }}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<Button type="button" variant="outline" size="sm" @click="emit('openDriverStore')">
|
<Button type="button" variant="outline" size="sm" @click="emit('openDriverStore', 'jdbc')">
|
||||||
<FolderOpen class="h-3.5 w-3.5" />
|
<FolderOpen class="h-3.5 w-3.5" />
|
||||||
{{ t("toolbar.driverManager") }}
|
{{ t("toolbar.driverManager") }}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const emit = defineEmits<{
|
|||||||
connectStarted: [name: string];
|
connectStarted: [name: string];
|
||||||
connectSucceeded: [name: string];
|
connectSucceeded: [name: string];
|
||||||
connectFailed: [message: string];
|
connectFailed: [message: string];
|
||||||
openDriverStore: [];
|
openDriverStore: [tab?: "jdbc"];
|
||||||
openTunnelProfileSettings: [];
|
openTunnelProfileSettings: [];
|
||||||
openLineageTarget: [
|
openLineageTarget: [
|
||||||
target: {
|
target: {
|
||||||
@@ -136,7 +136,7 @@ watch(
|
|||||||
@connect-started="emit('connectStarted', $event)"
|
@connect-started="emit('connectStarted', $event)"
|
||||||
@connect-succeeded="emit('connectSucceeded', $event)"
|
@connect-succeeded="emit('connectSucceeded', $event)"
|
||||||
@connect-failed="emit('connectFailed', $event)"
|
@connect-failed="emit('connectFailed', $event)"
|
||||||
@open-driver-store="emit('openDriverStore')"
|
@open-driver-store="emit('openDriverStore', $event)"
|
||||||
@open-tunnel-profile-settings="emit('openTunnelProfileSettings')"
|
@open-tunnel-profile-settings="emit('openTunnelProfileSettings')"
|
||||||
/>
|
/>
|
||||||
<DangerConfirmDialog
|
<DangerConfirmDialog
|
||||||
|
|||||||
@@ -322,6 +322,7 @@ export default {
|
|||||||
kafkaKerberosPathHint: "The keytab and krb5.conf paths are read by DBX Agent and must exist on the machine running DBX Agent; files are not uploaded from this browser.",
|
kafkaKerberosPathHint: "The keytab and krb5.conf paths are read by DBX Agent and must exist on the machine running DBX Agent; files are not uploaded from this browser.",
|
||||||
kafkaKerberosAuthHint: "Uses GSSAPI + keytab login. If the server requires encrypted transport, set Security to SASL_SSL; otherwise Auto or SASL_PLAINTEXT can be used.",
|
kafkaKerberosAuthHint: "Uses GSSAPI + keytab login. If the server requires encrypted transport, set Security to SASL_SSL; otherwise Auto or SASL_PLAINTEXT can be used.",
|
||||||
searchDatabasePlaceholder: "Search database types",
|
searchDatabasePlaceholder: "Search database types",
|
||||||
|
jdbcConnection: "JDBC connection",
|
||||||
iconView: "Icon view",
|
iconView: "Icon view",
|
||||||
listView: "List view",
|
listView: "List view",
|
||||||
selectedDatabase: "Selected",
|
selectedDatabase: "Selected",
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ export default withEnglishFallback({
|
|||||||
nacosTlsSkipVerify: "Omitir verificación de certificado",
|
nacosTlsSkipVerify: "Omitir verificación de certificado",
|
||||||
nacosPageSize: "Tamaño de página",
|
nacosPageSize: "Tamaño de página",
|
||||||
searchDatabasePlaceholder: "Buscar tipos de bases de datos",
|
searchDatabasePlaceholder: "Buscar tipos de bases de datos",
|
||||||
|
jdbcConnection: "Conexión JDBC",
|
||||||
iconView: "Vista de íconos",
|
iconView: "Vista de íconos",
|
||||||
listView: "Vista de lista",
|
listView: "Vista de lista",
|
||||||
selectedDatabase: "Seleccionada",
|
selectedDatabase: "Seleccionada",
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ export default withEnglishFallback({
|
|||||||
nacosTlsSkipVerify: "Salta verifica certificato",
|
nacosTlsSkipVerify: "Salta verifica certificato",
|
||||||
nacosPageSize: "Dimensione pagina",
|
nacosPageSize: "Dimensione pagina",
|
||||||
searchDatabasePlaceholder: "Cerca tipi di database",
|
searchDatabasePlaceholder: "Cerca tipi di database",
|
||||||
|
jdbcConnection: "Connessione JDBC",
|
||||||
iconView: "Vista icone",
|
iconView: "Vista icone",
|
||||||
listView: "Vista elenco",
|
listView: "Vista elenco",
|
||||||
selectedDatabase: "Selezionato",
|
selectedDatabase: "Selezionato",
|
||||||
|
|||||||
@@ -295,6 +295,7 @@ export default withEnglishFallback({
|
|||||||
nacosTlsSkipVerify: "証明書検証をスキップ",
|
nacosTlsSkipVerify: "証明書検証をスキップ",
|
||||||
nacosPageSize: "ページサイズ",
|
nacosPageSize: "ページサイズ",
|
||||||
searchDatabasePlaceholder: "データベースタイプを検索",
|
searchDatabasePlaceholder: "データベースタイプを検索",
|
||||||
|
jdbcConnection: "JDBC 接続",
|
||||||
iconView: "アイコン表示",
|
iconView: "アイコン表示",
|
||||||
listView: "リスト表示",
|
listView: "リスト表示",
|
||||||
selectedDatabase: "選択中",
|
selectedDatabase: "選択中",
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ export default withEnglishFallback({
|
|||||||
nacosTlsSkipVerify: "Ignorar verificação do certificado",
|
nacosTlsSkipVerify: "Ignorar verificação do certificado",
|
||||||
nacosPageSize: "Tamanho da página",
|
nacosPageSize: "Tamanho da página",
|
||||||
searchDatabasePlaceholder: "Pesquisar tipos de banco de dados",
|
searchDatabasePlaceholder: "Pesquisar tipos de banco de dados",
|
||||||
|
jdbcConnection: "Conexão JDBC",
|
||||||
iconView: "Visualização em ícones",
|
iconView: "Visualização em ícones",
|
||||||
listView: "Visualização em lista",
|
listView: "Visualização em lista",
|
||||||
selectedDatabase: "Selecionado",
|
selectedDatabase: "Selecionado",
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ export default withEnglishFallback({
|
|||||||
kafkaKerberosPathHint: "keytab 和 krb5.conf 路径由 DBX Agent 读取,必须存在于运行 DBX Agent 的机器上;不会从当前浏览器上传文件。",
|
kafkaKerberosPathHint: "keytab 和 krb5.conf 路径由 DBX Agent 读取,必须存在于运行 DBX Agent 的机器上;不会从当前浏览器上传文件。",
|
||||||
kafkaKerberosAuthHint: "使用 GSSAPI + keytab 登录。若服务端要求加密传输,请将 Security 设为 SASL_SSL;否则可使用 Auto 或 SASL_PLAINTEXT。",
|
kafkaKerberosAuthHint: "使用 GSSAPI + keytab 登录。若服务端要求加密传输,请将 Security 设为 SASL_SSL;否则可使用 Auto 或 SASL_PLAINTEXT。",
|
||||||
searchDatabasePlaceholder: "搜索数据库类型",
|
searchDatabasePlaceholder: "搜索数据库类型",
|
||||||
|
jdbcConnection: "JDBC 连接",
|
||||||
iconView: "图标视图",
|
iconView: "图标视图",
|
||||||
listView: "列表视图",
|
listView: "列表视图",
|
||||||
selectedDatabase: "已选择",
|
selectedDatabase: "已选择",
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ export default withEnglishFallback({
|
|||||||
nacosTlsSkipVerify: "跳過憑證驗證",
|
nacosTlsSkipVerify: "跳過憑證驗證",
|
||||||
nacosPageSize: "分頁大小",
|
nacosPageSize: "分頁大小",
|
||||||
searchDatabasePlaceholder: "搜尋資料庫類型",
|
searchDatabasePlaceholder: "搜尋資料庫類型",
|
||||||
|
jdbcConnection: "JDBC 連線",
|
||||||
iconView: "圖示檢視",
|
iconView: "圖示檢視",
|
||||||
listView: "清單檢視",
|
listView: "清單檢視",
|
||||||
selectedDatabase: "已選擇",
|
selectedDatabase: "已選擇",
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { test } from "vitest";
|
||||||
|
|
||||||
|
function source(relativePath: string): string {
|
||||||
|
return readFileSync(path.resolve(relativePath), "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
test("keeps JDBC outside the database picker and exposes a dedicated entry", () => {
|
||||||
|
const content = source("apps/desktop/src/components/connection/ConnectionDialog.vue");
|
||||||
|
const optionsStart = content.indexOf("const dbOptions: DbOption[] = [");
|
||||||
|
const optionsEnd = content.indexOf("const dbCategories", optionsStart);
|
||||||
|
const pickerToolbar = content.indexOf("sm:justify-between");
|
||||||
|
const searchInput = content.indexOf('v-model="dbSearchQuery"', pickerToolbar);
|
||||||
|
const jdbcEntry = content.indexOf("data-jdbc-connection-entry", pickerToolbar);
|
||||||
|
|
||||||
|
assert.notEqual(optionsStart, -1);
|
||||||
|
assert.notEqual(optionsEnd, -1);
|
||||||
|
assert.equal(content.slice(optionsStart, optionsEnd).includes('{ value: "jdbc"'), false);
|
||||||
|
assert.ok(pickerToolbar < searchInput && searchInput < jdbcEntry);
|
||||||
|
assert.match(content.slice(jdbcEntry, jdbcEntry + 400), /goToConnectionStep\('jdbc'\)/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("opens driver management on the JDBC tab from JDBC connection settings", () => {
|
||||||
|
const connectionDialog = source("apps/desktop/src/components/connection/ConnectionDialog.vue");
|
||||||
|
const appDialogs = source("apps/desktop/src/components/layout/AppDialogs.vue");
|
||||||
|
const app = source("apps/desktop/src/App.vue");
|
||||||
|
const driverStore = source("apps/desktop/src/components/config/DriverStoreDialog.vue");
|
||||||
|
|
||||||
|
assert.equal(connectionDialog.match(/emit\('openDriverStore', 'jdbc'\)/g)?.length, 2);
|
||||||
|
assert.match(appDialogs, /@open-driver-store="emit\('openDriverStore', \$event\)"/);
|
||||||
|
assert.match(app, /openDriverStorePage\(\$event\)/);
|
||||||
|
assert.match(app, /v-model:active-tab="driverStoreActiveTab"/);
|
||||||
|
assert.match(driverStore, /"update:activeTab": \[tab: "agent" \| "jdbc" \| "storage" \| "runtime"\]/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("resets the driver management tab after the page is closed", () => {
|
||||||
|
const app = source("apps/desktop/src/App.vue");
|
||||||
|
const closeStart = app.indexOf("function closeDriverStorePage() {");
|
||||||
|
const closeEnd = app.indexOf("\n}", closeStart);
|
||||||
|
|
||||||
|
assert.notEqual(closeStart, -1);
|
||||||
|
assert.notEqual(closeEnd, -1);
|
||||||
|
assert.match(app.slice(closeStart, closeEnd), /driverStoreActiveTab\.value = "agent"/);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user