fix(query): show timeout settings for structured errors

This commit is contained in:
zipg authored and GitHub committed 2026-08-13 12:57:29 +08:00
1 parent c51abd2178
commit 0f86614679
5 files changed
+67 -4

No files matched your search

@@ -2,10 +2,12 @@
import { Bot, Wrench } from "@lucide/vue";
import { useI18n } from "vue-i18n";
import { Button } from "@/components/ui/button";
import type { BackendError } from "@/lib/backend/errorUtils";
import { isQueryTimeoutErrorMessage } from "@/lib/sql/queryError";
const props = defineProps<{
errorMessage: string;
backendError?: BackendError;
connectionId?: string;
}>();
@@ -18,7 +20,7 @@ const { t } = useI18n();
</script>
<template>
<Button v-if="connectionId && isQueryTimeoutErrorMessage(errorMessage)" variant="outline" size="sm" class="h-7 gap-1.5 px-2.5 text-xs" @click="emit('changeQueryTimeout')">
<Button v-if="connectionId && isQueryTimeoutErrorMessage(errorMessage, backendError)" variant="outline" size="sm" class="h-7 gap-1.5 px-2.5 text-xs" @click="emit('changeQueryTimeout')">
<Wrench class="h-3.5 w-3.5" />
{{ t("editor.changeQueryTimeout") }}
</Button>
@@ -1634,7 +1634,13 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
/>
</template>
<template v-if="activeTab.result && isQueryExecutionErrorResult(activeTab.result)" #error-actions="{ errorMessage }">
<QueryErrorActions :error-message="String(errorMessage)" :connection-id="activeTab.connectionId" @change-query-timeout="activeTab.connectionId && emit('openConnectionSettings', activeTab.connectionId, 'advanced')" @fix-with-ai="(message) => emit('fixWithAi', message)" />
<QueryErrorActions
:error-message="String(errorMessage)"
:backend-error="activeTab.result.error"
:connection-id="activeResultConnectionId"
@change-query-timeout="activeResultConnectionId && emit('openConnectionSettings', activeResultConnectionId, 'advanced')"
@fix-with-ai="(message) => emit('fixWithAi', message)"
/>
</template>
</DataGrid>
<QueryLoadingState
@@ -1962,7 +1968,13 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
@sort="(column: string, columnIndex: number, direction: 'asc' | 'desc' | null, whereInput?: string, mode?: DataGridSortMode) => emit('sort', column, columnIndex, direction, whereInput, mode)"
>
<template v-if="activeTab.result && isQueryExecutionErrorResult(activeTab.result)" #error-actions="{ errorMessage }">
<QueryErrorActions :error-message="String(errorMessage)" :connection-id="activeTab.connectionId" @change-query-timeout="activeTab.connectionId && emit('openConnectionSettings', activeTab.connectionId, 'advanced')" @fix-with-ai="(message) => emit('fixWithAi', message)" />
<QueryErrorActions
:error-message="String(errorMessage)"
:backend-error="activeTab.result.error"
:connection-id="activeResultConnectionId"
@change-query-timeout="activeResultConnectionId && emit('openConnectionSettings', activeResultConnectionId, 'advanced')"
@fix-with-ai="(message) => emit('fixWithAi', message)"
/>
</template>
</DataGrid>
<QueryLoadingState v-else-if="activeTab.isExecuting" class="h-full" :label-key="queryExecutionLabelKey(activeTab)" :elapsed-seconds="queryRunningElapsedSeconds" show-cancel :cancel-disabled="!canCancelQueryExecution(activeTab)" :cancelling="activeTab.isCancelling" @cancel="emit('cancel')" />
+27
View File
@@ -26,6 +26,33 @@ describe("isQueryTimeoutErrorMessage", () => {
expect(isQueryTimeoutErrorMessage("Agent RPC error (-1): Agent RPC call timed out (120s)")).toBe(true);
});
it("detects structured query operation timeouts before localized text matching", () => {
const timeoutError = {
version: 1,
code: "DBX-JDBC-2002",
messageKey: "backendErrors.jdbc.operationTimedOut",
messageParams: { stage: "execute" },
source: "jdbcAgent",
operationOutcome: "unknown" as const,
} as const;
expect(isQueryTimeoutErrorMessage("数据库操作超时(阶段:execute)。", timeoutError)).toBe(true);
expect(isQueryTimeoutErrorMessage("Database operation timed out (stage: fetch).", { ...timeoutError, messageParams: { stage: "fetch" } })).toBe(true);
});
it("does not offer query timeout settings for structured infrastructure timeouts", () => {
const timeoutError = {
version: 1,
code: "DBX-JDBC-2001",
messageKey: "backendErrors.jdbc.operationTimedOut",
messageParams: { stage: "connect" },
source: "jdbcAgent",
operationOutcome: "not_started" as const,
} as const;
expect(isQueryTimeoutErrorMessage("Database operation timed out (stage: connect).", timeoutError)).toBe(false);
});
it("does not classify unrelated errors as query timeouts", () => {
expect(isQueryTimeoutErrorMessage('syntax error at or near "select"')).toBe(false);
expect(isQueryTimeoutErrorMessage("Connection timed out while loading databases")).toBe(false);
+9 -1
View File
@@ -1,4 +1,12 @@
export function isQueryTimeoutErrorMessage(message: string): boolean {
import type { BackendError } from "@/lib/backend/errorUtils";
const QUERY_TIMEOUT_STAGES = new Set(["execute", "fetch"]);
export function isQueryTimeoutErrorMessage(message: string, backendError?: BackendError): boolean {
if (backendError?.messageKey === "backendErrors.jdbc.operationTimedOut") {
const stage = String(backendError.messageParams.stage ?? "").toLowerCase();
return QUERY_TIMEOUT_STAGES.has(stage);
}
const lower = message.toLowerCase();
if (lower.includes("query timed out") || lower.includes("查询超时") || lower.includes("查詢逾時")) return true;
// Agent RPC client-side timeout (tokio::time::timeout in agent_driver.rs). This is the