fix(import): timeout and retry existing-table column load

This commit is contained in:
Melody Ruch authored and GitHub committed 2026-09-04 16:52:00 +08:00
1 parent 7f7f011f40
commit a2e4d15bbc
10 files changed
+43 -4

No files matched your search

@@ -64,6 +64,25 @@ interface BatchImportTask {
}
const SKIP_VALUE = "__skip__";
const TARGET_COLUMNS_TIMEOUT_MS = 15000;
const TARGET_COLUMNS_TIMEOUT = Symbol("target-columns-timeout");
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
return new Promise<T>((resolve, reject) => {
const timer = setTimeout(() => reject(TARGET_COLUMNS_TIMEOUT), ms);
promise.then(
(value) => {
clearTimeout(timer);
resolve(value);
},
(error) => {
clearTimeout(timer);
reject(error);
},
);
});
}
const targetColumns = ref<ColumnInfo[]>([]);
const loadedTargetTableName = ref("");
const existingTableNames = ref<string[]>([]);
@@ -519,7 +538,7 @@ async function loadTargetColumns() {
errorMessage.value = "";
try {
await store.ensureConnected(props.prefillConnectionId);
const columns = await api.getColumns(props.prefillConnectionId, props.prefillDatabase, targetSchema.value, tableName);
const columns = await withTimeout(api.getColumns(props.prefillConnectionId, props.prefillDatabase, targetSchema.value, tableName), TARGET_COLUMNS_TIMEOUT_MS);
if (requestId !== targetColumnsRequestId) return;
targetColumns.value = columns;
loadedTargetTableName.value = tableName;
@@ -529,7 +548,7 @@ async function loadTargetColumns() {
targetColumns.value = [];
loadedTargetTableName.value = "";
columnMapping.value = {};
errorMessage.value = String(e?.message || e);
errorMessage.value = e === TARGET_COLUMNS_TIMEOUT ? t("tableImport.targetColumnsTimeout") : String(e?.message || e);
}
} finally {
if (requestId === targetColumnsRequestId) loadingTarget.value = false;
@@ -1555,8 +1574,11 @@ watch(rawProgressPercent, (percent) => {
<Loader2 class="h-3.5 w-3.5 animate-spin" />
{{ t("common.loading") }}
</div>
<div v-if="errorMessage && wizardStep !== 'execution'" class="rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
{{ errorMessage }}
<div v-if="errorMessage && wizardStep !== 'execution'" class="flex items-center gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
<span class="flex-1">{{ errorMessage }}</span>
<Button v-if="targetMode === 'existing' && !loadingTarget && !existingTargetMetadataReady" variant="outline" size="sm" class="h-6 px-2 text-xs" @click="loadTargetColumns()">
{{ t("tableImport.retry") }}
</Button>
</div>
</div>
@@ -268,6 +268,7 @@ describe("TableImportDialog existing targets", () => {
await vi.waitFor(() => {
expect(mocks.getColumns).toHaveBeenCalledWith("connection-1", "main", "main", "existing_target");
});
await vi.waitFor(() => expect(buttonContaining("Next")?.disabled).toBe(false));
buttonContaining("Next")?.click();
await flushAsyncUpdates();
+2
View File
@@ -5536,6 +5536,8 @@ export default {
searchExistingTables: "Search tables...",
loadingTables: "Loading tables...",
noTables: "No tables available",
targetColumnsTimeout: "Loading target table columns timed out. Check the connection and try again.",
retry: "Retry",
stepSource: "Source",
stepOptions: "Options",
stepMapping: "Mapping",
+2
View File
@@ -5331,6 +5331,8 @@ export default withEnglishFallback({
status_done: "Import complete",
status_error: "Import failed",
status_cancelled: "Import cancelled",
targetColumnsTimeout: "Se agotó el tiempo de espera al cargar los campos de la tabla de destino. Compruebe la conexión e inténtelo de nuevo.",
retry: "Reintentar",
},
dataGenerate: {
title: "Generación de datos",
+2
View File
@@ -5329,6 +5329,8 @@ export default withEnglishFallback({
status_done: "Import complete",
status_error: "Import failed",
status_cancelled: "Import cancelled",
targetColumnsTimeout: "Timeout nel caricamento dei campi della tabella di destinazione. Controlla la connessione e riprova.",
retry: "Riprova",
},
dataGenerate: {
title: "Generazione dati",
+2
View File
@@ -5367,6 +5367,8 @@ export default withEnglishFallback({
titleRow: "ヘッダー行(0 はなし)",
dataStartRow: "データ開始行",
lastDataRow: "データ終了行(0 は末尾まで)",
targetColumnsTimeout: "ターゲットテーブルのフィールド読み込みがタイムアウトしました。接続を確認して再試行してください。",
retry: "再試行",
},
dataGenerate: {
title: "データ生成",
+2
View File
@@ -5028,6 +5028,8 @@ export default withEnglishFallback({
status_done: "가져오기 완료",
status_error: "가져오기 실패",
status_cancelled: "가져오기 취소됨",
targetColumnsTimeout: "대상 테이블 필드를 로드하는 시간이 초과되었습니다. 연결을 확인한 후 다시 시도하십시오.",
retry: "재시도",
},
dataGenerate: {
title: "데이터 생성",
+2
View File
@@ -5331,6 +5331,8 @@ export default withEnglishFallback({
status_done: "Import complete",
status_error: "Import failed",
status_cancelled: "Import cancelled",
targetColumnsTimeout: "Tempo esgotado ao carregar os campos da tabela de destino. Verifique a conexão e tente novamente.",
retry: "Tentar novamente",
},
dataGenerate: {
title: "Geração de dados",
+2
View File
@@ -5520,6 +5520,8 @@ export default withEnglishFallback({
searchExistingTables: "搜索表...",
loadingTables: "正在加载表...",
noTables: "暂无可用表",
targetColumnsTimeout: "加载目标表字段超时,请检查连接后重试。",
retry: "重试",
stepSource: "来源",
stepOptions: "选项",
stepMapping: "映射",
+2
View File
@@ -4654,6 +4654,8 @@ export default withEnglishFallback({
status_done: "匯入完成",
status_error: "匯入失敗",
status_cancelled: "匯入已取消",
targetColumnsTimeout: "載入目標資料表欄位逾時,請檢查連線後重試。",
retry: "重試",
},
dataGenerate: {
title: "資料生成",