diff --git a/apps/desktop/src/components/document/DocumentBrowser.vue b/apps/desktop/src/components/document/DocumentBrowser.vue
index 09010d42bb..ebb0451f39 100644
--- a/apps/desktop/src/components/document/DocumentBrowser.vue
+++ b/apps/desktop/src/components/document/DocumentBrowser.vue
@@ -13,6 +13,7 @@ import ErrorBanner from "@/components/ui/ErrorBanner.vue";
import DataGrid from "@/components/grid/DataGrid.vue";
import QueryLoadingState from "@/components/common/QueryLoadingState.vue";
import * as api from "@/lib/api";
+import { useConnectionStore } from "@/stores/connectionStore";
import { clampSearchSplitWidth } from "@/lib/dataGridSearchSplit";
import { documentViewerFontStyle } from "@/lib/documentViewerFontStyle";
import { buildDocumentFilterCondition, combineDocumentFilterConditions, currentDocumentFilterJson, defaultDocumentFilterRule, documentFilterModeNeedsValue, documentFilterModeOptions, documentStoreProviderFor, type DocumentFilterMode, type DocumentFilterRule } from "@/lib/documentStoreProvider";
@@ -28,6 +29,7 @@ import "splitpanes/dist/splitpanes.css";
const { t } = useI18n();
const settingsStore = useSettingsStore();
+const connectionStore = useConnectionStore();
const props = defineProps<{
connectionId: string;
@@ -714,7 +716,14 @@ function highlightedJson(json: string): string {
});
}
-onMounted(load);
+onMounted(async () => {
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
+ load();
+});
onBeforeUnmount(() => {
if (documentLoadExecutionId.value) void api.cancelQuery(documentLoadExecutionId.value);
stopDocumentLoadingTimer();
diff --git a/apps/desktop/src/components/kv/KvKeyBrowser.vue b/apps/desktop/src/components/kv/KvKeyBrowser.vue
index ee9de8c7b4..706656d1e7 100644
--- a/apps/desktop/src/components/kv/KvKeyBrowser.vue
+++ b/apps/desktop/src/components/kv/KvKeyBrowser.vue
@@ -1,6 +1,7 @@
diff --git a/apps/desktop/src/components/mq/MqAdminConsole.vue b/apps/desktop/src/components/mq/MqAdminConsole.vue
index 6f8b2e8866..5f28c07f23 100644
--- a/apps/desktop/src/components/mq/MqAdminConsole.vue
+++ b/apps/desktop/src/components/mq/MqAdminConsole.vue
@@ -3,6 +3,7 @@ import { formatError } from "@/lib/errorUtils";
import { ref, computed, onMounted, watch } from "vue";
import type { MqClusterInfo, TopicInfo } from "@/types/mq";
import { mqTestConnection } from "@/lib/api";
+import { useConnectionStore } from "@/stores/connectionStore";
import { mqClusterOptionsFromExtra } from "@/lib/mqTenantForm";
import TenantsPanel from "./TenantsPanel.vue";
import NamespacesPanel from "./NamespacesPanel.vue";
@@ -21,6 +22,7 @@ interface Props {
}
const props = defineProps();
+const connectionStore = useConnectionStore();
type MqTab = "tenants" | "namespaces" | "topics" | "subscriptions" | "monitoring" | "clients" | "policies" | "permissions" | "raw";
@@ -168,7 +170,12 @@ watch(
);
// Lifecycle
-onMounted(() => {
+onMounted(async () => {
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
loadClusterInfo();
});
diff --git a/apps/desktop/src/components/nacos/NacosAdminConsole.vue b/apps/desktop/src/components/nacos/NacosAdminConsole.vue
index c56e5c2e9a..930929d530 100644
--- a/apps/desktop/src/components/nacos/NacosAdminConsole.vue
+++ b/apps/desktop/src/components/nacos/NacosAdminConsole.vue
@@ -13,6 +13,7 @@ import EditorSearchPanel from "@/components/editor/EditorSearchPanel.vue";
import NacosConfigDiffDialog from "@/components/nacos/NacosConfigDiffDialog.vue";
import NacosConfigHistoryDialog from "@/components/nacos/NacosConfigHistoryDialog.vue";
import { useToast } from "@/composables/useToast";
+import { useConnectionStore } from "@/stores/connectionStore";
import { useI18n } from "vue-i18n";
import * as api from "@/lib/api";
import { buildNacosConfigDeleteConfirm, buildNacosConfigExportFileName, buildNacosConfigHistoryRollbackConfirm, buildNacosInstanceConfirm, createNacosSaveAsCopy, resolveNacosConfigCopyText } from "@/lib/nacosAdmin";
@@ -39,6 +40,7 @@ type AdminTab = "configs" | "services";
const { toast } = useToast();
const { t } = useI18n();
const settingsStore = useSettingsStore();
+const connectionStore = useConnectionStore();
const { isDark } = useTheme();
const activeTab = ref("configs");
const connectionInfo = ref(null);
@@ -839,12 +841,22 @@ watch(
originalConfigContent.value = "";
destroyConfigEditor();
selectedService.value = null;
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
await loadInfo();
await Promise.all([loadConfigsWithRetry(1), loadServicesWithRetry(1)]);
},
);
onMounted(async () => {
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
await loadInfo();
await Promise.all([loadConfigsWithRetry(1), loadServicesWithRetry(1)]);
});
diff --git a/apps/desktop/src/components/objects/ObjectBrowser.vue b/apps/desktop/src/components/objects/ObjectBrowser.vue
index da9fdf532c..a254f30b60 100644
--- a/apps/desktop/src/components/objects/ObjectBrowser.vue
+++ b/apps/desktop/src/components/objects/ObjectBrowser.vue
@@ -1236,11 +1236,16 @@ onBeforeUnmount(() => {
watch(
() => [props.connection.id, props.database, props.schema] as const,
- () => {
+ async () => {
selectedSchema.value = props.schema;
userHasSelectedFilter.value = false;
objectFilter.value = "all";
clearTableSelection();
+ try {
+ await connectionStore.ensureConnected(props.connection.id);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connection.id, e);
+ }
void reload();
},
{ immediate: true },
diff --git a/apps/desktop/src/components/redis/RedisDashboard.vue b/apps/desktop/src/components/redis/RedisDashboard.vue
index 42b20020d4..e51b47b111 100644
--- a/apps/desktop/src/components/redis/RedisDashboard.vue
+++ b/apps/desktop/src/components/redis/RedisDashboard.vue
@@ -255,6 +255,11 @@ watch(autoRefreshInterval, () => {
// Lifecycle
// ---------------------------------------------------------------------------
onMounted(async () => {
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
await fetchClusterNodes();
await fetchInfo();
});
diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.vue b/apps/desktop/src/components/redis/RedisKeyBrowser.vue
index ce80f1c7b6..6091931d75 100644
--- a/apps/desktop/src/components/redis/RedisKeyBrowser.vue
+++ b/apps/desktop/src/components/redis/RedisKeyBrowser.vue
@@ -921,12 +921,29 @@ function onCommandInputKeydown(event: KeyboardEvent) {
}
}
-onMounted(() => {
+onMounted(async () => {
resumeRedisBrowserBackgroundWork();
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
void loadKeys();
});
-onActivated(resumeRedisBrowserBackgroundWork);
+onActivated(async () => {
+ resumeRedisBrowserBackgroundWork();
+ // Ensure the connection is still alive after reactivation (e.g. tab switch).
+ // If keys failed to load previously (empty list), retry loading.
+ try {
+ await connectionStore.ensureConnected(props.connectionId);
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
+ }
+ if (flatKeys.value.length === 0 && !loading.value) {
+ void loadKeys();
+ }
+});
onDeactivated(pauseRedisBrowserBackgroundWork);
diff --git a/apps/desktop/src/components/redis/RedisSlowlogPanel.vue b/apps/desktop/src/components/redis/RedisSlowlogPanel.vue
index a8700237df..c3efbdb069 100644
--- a/apps/desktop/src/components/redis/RedisSlowlogPanel.vue
+++ b/apps/desktop/src/components/redis/RedisSlowlogPanel.vue
@@ -59,9 +59,10 @@ const showClientColumns = computed(() => {
onMounted(async () => {
if (connectionMode.value === "cluster") {
try {
+ await connectionStore.ensureConnected(props.connectionId);
nodes.value = await api.redisClusterMasterNodes(props.connectionId);
- } catch {
- // Silently fail — nodes list is best-effort
+ } catch (e) {
+ console.warn("[DBX] ensureConnected failed for", props.connectionId, e);
}
}
});
diff --git a/apps/desktop/src/components/sidebar/TreeItem.vue b/apps/desktop/src/components/sidebar/TreeItem.vue
index bd26335cf5..85c2bb3457 100644
--- a/apps/desktop/src/components/sidebar/TreeItem.vue
+++ b/apps/desktop/src/components/sidebar/TreeItem.vue
@@ -494,30 +494,38 @@ async function toggle() {
await connectionStore.loadDatabases(node.connectionId);
}
} else if (node.type === "redis-db" && node.connectionId && node.database) {
+ await connectionStore.ensureConnected(node.connectionId);
const tabTitle = `${connectionStore.getConfig(node.connectionId)?.name || "Redis"}:db${node.database}`;
queryStore.createTab(node.connectionId, node.database, tabTitle, "redis");
} else if (node.type === "mq-tenant" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
queryStore.openMqAdmin(node.connectionId, { tenant: node.mqTenant || node.label });
} else if (node.type === "nacos-namespace" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
queryStore.openNacosAdmin(node.connectionId, { namespace: node.nacosNamespace || "", namespaceName: node.nacosNamespaceName || node.label });
} else if (node.type === "etcd-root" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
const tabTitle = `${connectionStore.getConfig(node.connectionId)?.name || "etcd"}:keys`;
queryStore.createTab(node.connectionId, "", tabTitle, "etcd");
refreshActiveKvBrowserAfterOpen("etcd", node.connectionId);
} else if (node.type === "zookeeper-root" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
const tabTitle = `${connectionStore.getConfig(node.connectionId)?.name || "ZooKeeper"}:keys`;
queryStore.createTab(node.connectionId, "", tabTitle, "zookeeper");
refreshActiveKvBrowserAfterOpen("zookeeper", node.connectionId);
} else if (node.type === "user-admin" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
queryStore.openUserAdmin(node.connectionId);
} else if (node.type === "mongo-db" && node.connectionId && node.database) {
await connectionStore.loadMongoCollections(node.connectionId, node.database);
} else if (node.type === "mongo-collection" && node.connectionId && node.database) {
await connectionStore.loadTableGroups(node.connectionId, node.database, node.label, node.schema, node.id);
} else if (node.type === "elasticsearch-index" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
const tab = queryStore.createTab(node.connectionId, node.database || "default", node.label, "mongo");
queryStore.updateSql(tab, node.label);
} else if (node.type === "vector-collection" && node.connectionId) {
+ await connectionStore.ensureConnected(node.connectionId);
const collectionRef = node.id.includes("__vector_collection:") ? node.id.split("__vector_collection:").pop() || node.label : node.label;
const tab = queryStore.createTab(node.connectionId, node.database || "default", node.label, "vector");
queryStore.updateSql(tab, collectionRef);