feat(welcome): show recently opened connections

Closes #6015
This commit is contained in:
t8y2 committed 2026-08-13 12:19:21 +00:00
1 parent e0a7bc996d
commit de72675b67
3 files changed
+169 -1

No files matched your search

+15 -1
View File
@@ -46,6 +46,7 @@ import { translateBackendError } from "@/i18n/backend-errors";
import * as api from "@/lib/backend/api";
import { connectionRedactedNameLabel } from "@/lib/connection/connectionPresentation";
import { quickConnectionOpenTarget } from "@/lib/connection/connectionOpenTarget";
import { parseRecentConnectionIds, rankRecentConnections, RECENT_CONNECTION_IDS_STORAGE_KEY, recordRecentConnection } from "@/lib/connection/recentConnections";
import { resolveDefaultDatabase } from "@/lib/database/defaultDatabase";
import { normalizeSqliteNamespace } from "@/lib/database/sqliteNamespace";
import { findTreeNodeById, resolveNewQueryTarget, resolveNewQueryInitialSql } from "@/lib/sql/newQueryContext";
@@ -143,6 +144,7 @@ const queryStore = useQueryStore();
const settingsStore = useSettingsStore();
const savedSqlStore = useSavedSqlStore();
const promptTemplateStore = usePromptTemplateStore();
const recentConnectionIds = ref<readonly string[]>(parseRecentConnectionIds(safeLocalStorageGet(RECENT_CONNECTION_IDS_STORAGE_KEY)));
connectionStore.setBeforeConnectHandler(async (config) => {
await ensureJdbcxRuntimeDrivers(config, api);
const jdbcProductRuntimeBefore = JSON.stringify({
@@ -581,7 +583,18 @@ const connectionStats = computed(() => ({
connected: connectionStore.connectedIds.size,
types: new Set(connectionStore.connections.map((c) => c.driver_profile || c.db_type)).size,
}));
const recentConnections = computed(() => connectionStore.connections.slice(0, 5));
const recentConnections = computed(() => rankRecentConnections(connectionStore.connections, recentConnectionIds.value));
function rememberRecentConnection(connectionId: string | null) {
if (!connectionId) return;
const nextIds = recordRecentConnection(recentConnectionIds.value, connectionId);
if (nextIds === recentConnectionIds.value) return;
recentConnectionIds.value = nextIds;
safeLocalStorageSet(RECENT_CONNECTION_IDS_STORAGE_KEY, JSON.stringify(nextIds));
}
watch(() => connectionStore.activeConnectionId, rememberRecentConnection);
const savedSqlHistoryItems = computed(() => {
const folderById = new Map(savedSqlStore.allFolders.map((folder) => [folder.id, folder]));
const folderPath = (folderId?: string): string | undefined => {
@@ -1602,6 +1615,7 @@ async function newQuery() {
async function openConnectionQuery(connectionId: string) {
const connection = connectionStore.getConfig(connectionId);
if (!connection) return;
rememberRecentConnection(connectionId);
connectionStore.activeConnectionId = connectionId;
const initialTarget = quickConnectionOpenTarget(connection);
if (initialTarget.kind === "mq-admin") {
@@ -0,0 +1,62 @@
export const RECENT_CONNECTION_IDS_STORAGE_KEY = "dbx-recent-connection-ids-v1";
export const MAX_RECENT_CONNECTION_IDS = 5;
function normalizeRecentConnectionIds(ids: readonly unknown[]): string[] {
const normalized: string[] = [];
const seen = new Set<string>();
for (const value of ids) {
if (typeof value !== "string") continue;
const id = value.trim();
if (!id || seen.has(id)) continue;
seen.add(id);
normalized.push(id);
if (normalized.length === MAX_RECENT_CONNECTION_IDS) break;
}
return normalized;
}
export function parseRecentConnectionIds(raw: string | null): string[] {
if (!raw) return [];
try {
const parsed: unknown = JSON.parse(raw);
return Array.isArray(parsed) ? normalizeRecentConnectionIds(parsed) : [];
} catch {
return [];
}
}
export function recordRecentConnection(history: readonly string[], connectionId: string): readonly string[] {
const id = connectionId.trim();
const nextHistory = normalizeRecentConnectionIds(id ? [id, ...history] : history);
const unchanged = nextHistory.length === history.length && nextHistory.every((value, index) => value === history[index]);
return unchanged ? history : nextHistory;
}
export function rankRecentConnections<T extends { id: string }>(connections: readonly T[], history: readonly string[], limit = MAX_RECENT_CONNECTION_IDS): T[] {
const cappedLimit = Number.isFinite(limit) ? Math.max(0, Math.min(Math.floor(limit), MAX_RECENT_CONNECTION_IDS)) : MAX_RECENT_CONNECTION_IDS;
if (cappedLimit === 0) return [];
const connectionById = new Map(connections.map((connection) => [connection.id, connection]));
const ranked: T[] = [];
const selectedIds = new Set<string>();
for (const id of normalizeRecentConnectionIds(history)) {
const connection = connectionById.get(id);
if (!connection) continue;
ranked.push(connection);
selectedIds.add(id);
if (ranked.length === cappedLimit) return ranked;
}
for (const connection of connections) {
if (selectedIds.has(connection.id)) continue;
ranked.push(connection);
selectedIds.add(connection.id);
if (ranked.length === cappedLimit) break;
}
return ranked;
}