diff --git a/apps/desktop/src/components/import/TableImportDialog.vue b/apps/desktop/src/components/import/TableImportDialog.vue index bf561394d5..42e16166fb 100644 --- a/apps/desktop/src/components/import/TableImportDialog.vue +++ b/apps/desktop/src/components/import/TableImportDialog.vue @@ -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(promise: Promise, ms: number): Promise { + return new Promise((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([]); const loadedTargetTableName = ref(""); const existingTableNames = ref([]); @@ -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) => { {{ t("common.loading") }} -
- {{ errorMessage }} +
+ {{ errorMessage }} +
diff --git a/apps/desktop/src/components/import/__tests__/TableImportDialog.existingTarget.spec.ts b/apps/desktop/src/components/import/__tests__/TableImportDialog.existingTarget.spec.ts index 628b02218d..22608594f9 100644 --- a/apps/desktop/src/components/import/__tests__/TableImportDialog.existingTarget.spec.ts +++ b/apps/desktop/src/components/import/__tests__/TableImportDialog.existingTarget.spec.ts @@ -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(); diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 00a67c16c8..aae358608d 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -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", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 6963435269..cc2014cb10 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -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", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index cbb64e8749..2e2649d856 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -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", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index 83b0284236..575b53ffb7 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -5367,6 +5367,8 @@ export default withEnglishFallback({ titleRow: "ヘッダー行(0 はなし)", dataStartRow: "データ開始行", lastDataRow: "データ終了行(0 は末尾まで)", + targetColumnsTimeout: "ターゲットテーブルのフィールド読み込みがタイムアウトしました。接続を確認して再試行してください。", + retry: "再試行", }, dataGenerate: { title: "データ生成", diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts index a9f8d56794..7239893a02 100644 --- a/apps/desktop/src/i18n/locales/ko.ts +++ b/apps/desktop/src/i18n/locales/ko.ts @@ -5028,6 +5028,8 @@ export default withEnglishFallback({ status_done: "가져오기 완료", status_error: "가져오기 실패", status_cancelled: "가져오기 취소됨", + targetColumnsTimeout: "대상 테이블 필드를 로드하는 시간이 초과되었습니다. 연결을 확인한 후 다시 시도하십시오.", + retry: "재시도", }, dataGenerate: { title: "데이터 생성", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index 8be0791bf2..6c36d2eee8 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -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", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 92d3d4d947..4ce8b9b72d 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -5520,6 +5520,8 @@ export default withEnglishFallback({ searchExistingTables: "搜索表...", loadingTables: "正在加载表...", noTables: "暂无可用表", + targetColumnsTimeout: "加载目标表字段超时,请检查连接后重试。", + retry: "重试", stepSource: "来源", stepOptions: "选项", stepMapping: "映射", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 037916cf00..c666d40a48 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -4654,6 +4654,8 @@ export default withEnglishFallback({ status_done: "匯入完成", status_error: "匯入失敗", status_cancelled: "匯入已取消", + targetColumnsTimeout: "載入目標資料表欄位逾時,請檢查連線後重試。", + retry: "重試", }, dataGenerate: { title: "資料生成",