fix(llm): add fetch-models endpoint, fix SQL Lab INSERT (client_id truncation, sync mode, target_column, timestamp normalization)

- Add POST /api/llm/providers/fetch-models route with LLMClient.fetch_models()
- Add target_column to TranslationJob model/schema/service/orchestrator
- Fix SQL Lab execute: truncate client_id to 11 chars (varchar(11))
- Switch SQL Lab to sync mode (runAsync: false) — no Celery workers
- Fix polling: unwrap nested result from Superset query API
- Fix ClickHouse timestamp: normalize float timestamps to YYYY-MM-DD
This commit is contained in:
2026-05-13 20:06:15 +03:00
parent ffcfec9acf
commit 10803a5019
276 changed files with 1923 additions and 1822 deletions

View File

@@ -1,8 +1,7 @@
<!-- #region MigrationPage [C:4] [TYPE Page] [SEMANTICS sveltekit, migration, dashboard, dry-run, environment] -->
<!--
@COMPLEXITY: 3
@SEMANTICS: migration, dashboard, environment, dry-run, task-resume
@PURPOSE: Main migration dashboard page for environment selection, dry-run validation, and migration execution.
@BRIEF: Main migration dashboard page for environment selection, dry-run validation, and migration execution.
@LAYER: UI
@RELATION: [DEPENDS_ON] ->[frontend/src/lib/api.js]
@RELATION: [DEPENDS_ON] ->[stores]
@@ -52,7 +51,7 @@
<!-- @UX_FEEDBACK Modal dialogs for database mappings and password entry. -->
<!-- @UX_RECOVERY User can adjust selection, refresh databases, retry dry-run/migration. -->
<!--
@PURPOSE: Orchestrate migration UI workflow and route user actions to backend APIs and task store.
@BRIEF: Orchestrate migration UI workflow and route user actions to backend APIs and task store.
@PRE: API client and component dependencies are available; i18n store is initialized.
@POST: User can progress through selection, dry-run, migration start, and task resume flows.
@SIDE_EFFECT: Performs HTTP requests, mutates local UI state, updates selectedTask store.
@@ -114,7 +113,7 @@
const belief_scope = <T>(_id: string, fn: () => T): T => fn();
// [DEF:fetchEnvironments:Function]
// #region fetchEnvironments:Function [TYPE Function]
/**
* @purpose Fetches the list of environments from the API.
* @pre None.
@@ -134,9 +133,9 @@
}
});
}
// [/DEF:fetchEnvironments:Function]
// #endregion fetchEnvironments:Function
// [DEF:fetchDashboards:Function]
// #region fetchDashboards:Function [TYPE Function]
/**
* @purpose Fetches dashboards for the selected source environment.
* @pre envId is a valid environment ID.
@@ -157,13 +156,13 @@
}
});
}
// [/DEF:fetchDashboards:Function]
// #endregion fetchDashboards:Function
onMount(fetchEnvironments);
// [DEF:ReactiveDashboardFetch:Block]
// #region ReactiveDashboardFetch:Block [TYPE Function]
/**
* @PURPOSE: Automatically fetch dashboards when the source environment is changed.
* @BRIEF: Automatically fetch dashboards when the source environment is changed.
* @PRE: sourceEnvId is not empty.
* @POST: fetchDashboards is called with the new sourceEnvId.
* @UX_STATE: [Loading] -> Triggered when sourceEnvId changes.
@@ -173,9 +172,9 @@
console.info("[ReactiveDashboardFetch][REASON] Source environment changed, fetching dashboards", { sourceEnvId });
void fetchDashboards(sourceEnvId);
});
// [/DEF:ReactiveDashboardFetch:Block]
// #endregion ReactiveDashboardFetch:Block
// [DEF:fetchDatabases:Function]
// #region fetchDatabases:Function [TYPE Function]
/**
* @purpose Fetches databases from both environments and gets suggestions.
* @pre sourceEnvId and targetEnvId must be set.
@@ -221,9 +220,9 @@
}
});
}
// [/DEF:fetchDatabases:Function]
// #endregion fetchDatabases:Function
// [DEF:handleMappingUpdate:Function]
// #region handleMappingUpdate:Function [TYPE Function]
/**
* @purpose Saves a mapping to the backend.
* @pre event.detail contains sourceUuid and targetUuid.
@@ -262,10 +261,10 @@
}
});
}
// [/DEF:handleMappingUpdate:Function]
// #endregion handleMappingUpdate:Function
// [DEF:handleViewLogs:Function]
// @PURPOSE: Opens the log viewer for a specific task.
// #region handleViewLogs:Function [TYPE Function]
// @BRIEF: Opens the log viewer for a specific task.
// @PRE: event.detail contains task object.
// @POST: logViewer state updated and showLogViewer set to true.
function handleViewLogs(event: CustomEvent) {
@@ -276,10 +275,10 @@
showLogViewer = true;
});
}
// [/DEF:handleViewLogs:Function]
// #endregion handleViewLogs:Function
// [DEF:handlePasswordPrompt:Function]
// @PURPOSE: Reactive logic to show password prompt when a task is awaiting input.
// #region handlePasswordPrompt:Function [TYPE Function]
// @BRIEF: Reactive logic to show password prompt when a task is awaiting input.
// @PRE: selectedTask status is AWAITING_INPUT.
// @POST: showPasswordPrompt set to true with request data.
// This is triggered by TaskRunner or TaskHistory when a task needs input
@@ -287,9 +286,9 @@
// Ideally, TaskHistory or TaskRunner emits an event when input is needed.
// Or we watch selectedTask.
// [DEF:ReactivePasswordPrompt:Block]
// #region ReactivePasswordPrompt:Block [TYPE Function]
/**
* @PURPOSE: Monitor selected task for input requests and trigger password prompt.
* @BRIEF: Monitor selected task for input requests and trigger password prompt.
* @PRE: $selectedTask is not null and status is AWAITING_INPUT.
* @POST: showPasswordPrompt is set to true if input_request is database_password.
* @UX_STATE: [AwaitingInput] -> Password prompt modal is displayed.
@@ -311,11 +310,11 @@
showPasswordPrompt = true;
}
});
// [/DEF:ReactivePasswordPrompt:Block]
// [/DEF:handlePasswordPrompt:Function]
// #endregion ReactivePasswordPrompt:Block
// #endregion handlePasswordPrompt:Function
// [DEF:handleResumeMigration:Function]
// @PURPOSE: Resumes a migration task with provided passwords.
// #region handleResumeMigration:Function [TYPE Function]
// @BRIEF: Resumes a migration task with provided passwords.
// @PRE: event.detail contains passwords.
// @POST: resumeTask is called and showPasswordPrompt is hidden on success.
async function handleResumeMigration(event: CustomEvent) {
@@ -335,11 +334,11 @@
}
});
}
// [/DEF:handleResumeMigration:Function]
// #endregion handleResumeMigration:Function
// [DEF:startMigration:Function]
// #region startMigration:Function [TYPE Function]
/**
* @PURPOSE: Initiates the migration process by sending the selection to the backend.
* @BRIEF: Initiates the migration process by sending the selection to the backend.
* @PRE: sourceEnvId and targetEnvId are set and different; at least one dashboard is selected.
* @POST: A migration task is created and selectedTask store is updated.
* @SIDE_EFFECT: Resets dryRunResult; updates error state on failure.
@@ -412,11 +411,11 @@
}
});
}
// [/DEF:startMigration:Function]
// #endregion startMigration:Function
// [DEF:startDryRun:Function]
// #region startDryRun:Function [TYPE Function]
/**
* @PURPOSE: Performs a dry-run migration to identify potential risks and changes.
* @BRIEF: Performs a dry-run migration to identify potential risks and changes.
* @PRE: source/target environments and selected dashboards are valid.
* @POST: dryRunResult is populated with the pre-flight analysis.
* @UX_STATE: [Loading] -> [Success] or [Error]
@@ -469,13 +468,14 @@
}
});
}
// [/DEF:startDryRun:Function]
// [/DEF:MigrationDashboard:Component]
// #endregion startDryRun:Function
// #endregion MigrationDashboard:Component
</script>
<!-- #region MigrationDashboardView [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region MigrationDashboardView [C:2] [TYPE Block] [SEMANTICS migration, dashboard, layout, config] -->
<!-- @BRIEF Migration dashboard template wrapper: environment selector, dashboard grid, action buttons, dry-run results, and modals. -->
<!--
@PURPOSE: Render migration configuration controls, action CTAs, dry-run results, and modal entry points.
@BRIEF: Render migration configuration controls, action CTAs, dry-run results, and modal entry points.
@UX_STATE: Idle -> Configuration form is interactive.
@UX_STATE: Loading -> Loading messages and disabled buttons prevent duplicate actions.
@UX_STATE: Error -> Error banner is displayed without discarding current selection.
@@ -485,15 +485,18 @@
-->
<!-- [SECTION: TEMPLATE] -->
<div class="max-w-4xl mx-auto p-6">
<!-- #region MigrationHeader [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region MigrationHeader [C:2] [TYPE Block] [SEMANTICS migration, page-header] -->
<!-- @BRIEF Page header displaying the migration navigation title. -->
<PageHeader title={$t.nav.migration} />
<!-- #endregion MigrationHeader -->
<!-- #region TaskHistorySection [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region TaskHistorySection [C:2] [TYPE Block] [SEMANTICS migration, task-history] -->
<!-- @BRIEF Section showing recent migration task history. -->
<TaskHistory />
<!-- #endregion TaskHistorySection -->
<!-- #region ActiveTaskSection [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region ActiveTaskSection [C:2] [TYPE Block] [SEMANTICS migration, active-task] -->
<!-- @BRIEF Active task runner section shown when a migration task is selected. -->
{#if $selectedTask}
<div class="mt-6">
<TaskRunner />
@@ -518,7 +521,8 @@
</div>
{/if}
<!-- #region EnvironmentSelectionSection [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region EnvironmentSelectionSection [C:2] [TYPE Block] [SEMANTICS migration, environment-selection] -->
<!-- @BRIEF Source and target environment selector grid. -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<EnvSelector
label={$t.migration?.source_env }
@@ -534,6 +538,7 @@
<!-- #endregion EnvironmentSelectionSection -->
<!-- #region DashboardSelectionSection [C:2] [TYPE Component] [SEMANTICS migration, dashboard, selection, form] -->
<!-- @BRIEF Dashboard multi-select grid for choosing which dashboards to migrate. -->
<div class="mb-8">
<h2 class="text-lg font-medium mb-4">
{$t.migration?.select_dashboards_title }
@@ -554,7 +559,8 @@
</div>
<!-- #endregion DashboardSelectionSection -->
<!-- #region MigrationOptionsSection [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region MigrationOptionsSection [C:2] [TYPE Block] [SEMANTICS migration, options, config] -->
<!-- @BRIEF Migration options: cross-filter fix toggle and database replacement toggle. -->
<div class="mb-4">
<div class="flex items-center mb-2">
<input
@@ -640,7 +646,8 @@
</Button>
</div>
<!-- #region DryRunResultsSection [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region DryRunResultsSection [C:2] [TYPE Block] [SEMANTICS migration, dry-run, results] -->
<!-- @BRIEF Dry-run analysis results: diff summary cards, risk assessment, and full JSON details. -->
{#if dryRunResult}
<div class="mt-6 rounded-md border border-slate-200 bg-slate-50 p-4 space-y-3">
<h3 class="text-base font-semibold">Pre-flight Diff</h3>
@@ -685,9 +692,10 @@
{/if}
</div>
<!-- #region MigrationModals [C:2] [TYPE Block] [SEMANTICS ui,section] -->
<!-- #region MigrationModals [C:2] [TYPE Block] [SEMANTICS migration, modals, overlay] -->
<!-- @BRIEF Overlay modals for log viewer and password entry during migration. -->
<!--
@PURPOSE: Render overlay components for log viewing and password entry.
@BRIEF: Render overlay components for log viewing and password entry.
@UX_STATE: [LogViewing] -> TaskLogViewer is visible.
@UX_STATE: [AwaitingInput] -> PasswordPrompt is visible.
-->