fix(data): align table preview ordering

This commit is contained in:
t8y2 committed 2026-06-23 10:51:30 +08:00
1 parent 752a695018
commit 2f2fc36b18
6 files changed
+160 -117

No files matched your search

@@ -55,6 +55,7 @@ import { completionSchemasFromTree, completionTablesFromTree } from "@/lib/compl
const PINNED_TREE_NODES_STORAGE_KEY = "dbx-pinned-tree-nodes";
const ACTIVE_CONNECTION_STORAGE_KEY = "dbx-active-connection";
const CONNECTION_HEALTH_CHECK_TTL_MS = 2000;
function sidebarObjectGroupPageSize(): number {
const settingsStore = useSettingsStore();
const size = settingsStore.desktopSettings.sidebar_table_page_size;
@@ -146,6 +147,7 @@ export const useConnectionStore = defineStore("connection", () => {
const treeNodes = ref<TreeNode[]>([]);
const pinnedTreeNodeIds = ref<Set<string>>(new Set());
const connectedIds = ref<Set<string>>(new Set());
const lastConnectionHealthCheckAt = ref<Record<string, number>>({});
const loadedTreeNodeChildrenIds = ref<Set<string>>(new Set());
const connectionErrors = ref<Record<string, string>>({});
const editingConnectionId = ref<string | null>(null);
@@ -255,6 +257,20 @@ export const useConnectionStore = defineStore("connection", () => {
delete connectionErrors.value[connectionId];
}
function markConnectionHealthChecked(connectionId: string) {
lastConnectionHealthCheckAt.value[connectionId] = Date.now();
}
function clearConnectionHealthCheck(connectionId: string) {
if (!lastConnectionHealthCheckAt.value[connectionId]) return;
delete lastConnectionHealthCheckAt.value[connectionId];
}
function hasRecentConnectionHealthCheck(connectionId: string) {
const checkedAt = lastConnectionHealthCheckAt.value[connectionId];
return typeof checkedAt === "number" && Date.now() - checkedAt < CONNECTION_HEALTH_CHECK_TTL_MS;
}
function recordConnectionError(connectionId: string, error: unknown): string {
const message = connectionErrorMessage(error);
setConnectionError(connectionId, message);
@@ -263,6 +279,7 @@ export const useConnectionStore = defineStore("connection", () => {
function markConnectionLost(connectionId: string, error: unknown) {
connectedIds.value.delete(connectionId);
clearConnectionHealthCheck(connectionId);
if (activeConnectionId.value === connectionId) activeConnectionId.value = null;
recordConnectionError(connectionId, error);
}
@@ -733,6 +750,7 @@ export const useConnectionStore = defineStore("connection", () => {
for (const id of removedIds) {
clearConnectionError(id);
connectedIds.value.delete(id);
clearConnectionHealthCheck(id);
sidebarLayout.value = removeConnectionFromSidebarLayout(sidebarLayout.value, id);
}
rebuildTreeNodes();
@@ -763,6 +781,7 @@ export const useConnectionStore = defineStore("connection", () => {
connections.value = nextConnections;
rebuildTreeNodes();
connectedIds.value.delete(config.id);
clearConnectionHealthCheck(config.id);
invalidateCompletionCache(config.id);
clearLoadedChildrenCache(config.id);
const node = findNode(treeNodes.value, config.id);
@@ -851,6 +870,7 @@ export const useConnectionStore = defineStore("connection", () => {
const id = await withConnectionAttemptTimeout(api.connectDb(config), config);
activeConnectionId.value = id;
connectedIds.value.add(id);
markConnectionHealthChecked(id);
clearConnectionError(config.id);
if (id !== config.id) clearConnectionError(id);
@@ -897,6 +917,7 @@ export const useConnectionStore = defineStore("connection", () => {
break;
}
connectedIds.value.delete(connectionId);
clearConnectionHealthCheck(connectionId);
const node = findNode(treeNodes.value, connectionId);
if (node) {
node.isExpanded = false;
@@ -937,13 +958,16 @@ export const useConnectionStore = defineStore("connection", () => {
async function ensureConnected(connectionId: string) {
if (connectedIds.value.has(connectionId)) {
if (hasRecentConnectionHealthCheck(connectionId)) return;
// Optimistic: verify backend pool is actually healthy
try {
await api.checkConnectionHealth(connectionId);
markConnectionHealthChecked(connectionId);
return;
} catch {
// Backend pool is dead — remove from connectedIds and reconnect
connectedIds.value.delete(connectionId);
clearConnectionHealthCheck(connectionId);
if (activeConnectionId.value === connectionId) activeConnectionId.value = null;
}
}
@@ -961,6 +985,7 @@ export const useConnectionStore = defineStore("connection", () => {
await beforeConnectHandler?.(config);
await withConnectionAttemptTimeout(api.connectDb(config), config);
connectedIds.value.add(connectionId);
markConnectionHealthChecked(connectionId);
activeConnectionId.value = connectionId;
clearConnectionError(connectionId);
} catch (e) {
@@ -3080,6 +3105,7 @@ export const useConnectionStore = defineStore("connection", () => {
connections.value.push(normalized);
}
connectedIds.value.add(normalized.id);
markConnectionHealthChecked(normalized.id);
clearConnectionError(normalized.id);
}
+12 -6
View File
@@ -1260,6 +1260,8 @@ export const useQueryStore = defineStore("query", () => {
preserveResultDuringExecution?: boolean;
preserveTotalRowCountDuringExecution?: boolean;
skipRedisSafetyCheck?: boolean;
sourceTraceId?: string;
skipEnsureConnected?: boolean;
},
) {
const tab = tabs.value.find((t) => t.id === id);
@@ -1295,6 +1297,7 @@ export const useQueryStore = defineStore("query", () => {
connectionId: tab.connectionId,
database: tab.database,
schema: tab.schema,
sourceTraceId: options?.sourceTraceId,
sql,
});
const queryBaseSql = options?.resultBaseSql ?? sql;
@@ -1306,9 +1309,13 @@ export const useQueryStore = defineStore("query", () => {
let useAgentResultSession = false;
try {
const connStore = useConnectionStore();
console.info("[DBX][executeTabSql:ensure-connected:start]", { traceId, elapsed: elapsed() });
await connStore.ensureConnected(tab.connectionId);
console.info("[DBX][executeTabSql:ensure-connected:done]", { traceId, elapsed: elapsed() });
if (options?.skipEnsureConnected) {
console.info("[DBX][executeTabSql:ensure-connected:skip]", { traceId, elapsed: elapsed(), reason: "caller" });
} else {
console.info("[DBX][executeTabSql:ensure-connected:start]", { traceId, elapsed: elapsed() });
await connStore.ensureConnected(tab.connectionId);
console.info("[DBX][executeTabSql:ensure-connected:done]", { traceId, elapsed: elapsed() });
}
const conn = connStore.getConfig(tab.connectionId);
const effectiveDbType = effectiveDatabaseTypeForConnection(conn);
const useAgentCursor = conn?.db_type === "jdbc" || supportsDatabaseFeature(conn?.db_type, "driverManagement");
@@ -1586,7 +1593,7 @@ export const useQueryStore = defineStore("query", () => {
}
console.info("[DBX][executeTabSql:execute-multi:start]", { traceId, elapsed: elapsed() });
const clientSessionId = tab.mode === "query" || tab.mode === "data" ? tabClientSessionId(tab) : undefined;
const clientSessionId = tab.mode === "query" ? tabClientSessionId(tab) : undefined;
const executionOptions = {
...(typeof pageLimit === "number"
? useAgentResultSession
@@ -1606,6 +1613,7 @@ export const useQueryStore = defineStore("query", () => {
elapsed: elapsed(),
executionSchema,
optionKeys: Object.keys(executionOptions),
clientSession: Boolean(clientSessionId),
});
const executionPromise = api.executeMulti(tab.connectionId, tab.database, sqlToExecute, executionSchema, executionId, executionOptions);
const frontendTimeoutSecs = Math.max(queryTimeoutSecs * 2, 60);
@@ -2032,7 +2040,6 @@ export const useQueryStore = defineStore("query", () => {
const pageLimit = TABLE_DATA_EXPORT_PAGE_SIZE;
const effectiveDbType = effectiveDatabaseTypeForConnection(conn);
const primaryKeys = tab.tableMeta ? editablePrimaryKeys(effectiveDbType, tab.tableMeta.columns, tab.tableMeta.tableType) : tableMeta.primaryKeys;
const fallbackOrderColumns = effectiveDbType === "sqlserver" && !primaryKeys.length ? tableMeta.columns.slice(0, 1).map((column) => column.name) : undefined;
const sortOrder = tab.resultSortColumn && tab.resultSortDirection ? `${quoteTableIdentifier(effectiveDbType, tab.resultSortColumn)} ${tab.resultSortDirection.toUpperCase()}` : undefined;
const orderBy = tab.orderByInput?.trim() || sortOrder;
const queryTimeoutSecs = queryTimeoutSecsForConnection(conn);
@@ -2051,7 +2058,6 @@ export const useQueryStore = defineStore("query", () => {
tableName: tableMeta.tableName,
columns: tableMeta.columns.map((column) => column.name),
primaryKeys,
fallbackOrderColumns,
whereInput: tab.whereInput,
orderBy,
limit: pageLimit,