fix(frontend): target column mapping fields not loaded from job
Three fields were never loaded from backend job data: - targetLanguageColumn (job.target_language_column) - targetSourceColumn (job.target_source_column) - targetSourceLanguageColumn (job.target_source_language_column) Caused empty inputs in Target Config tab after page load. Also added missing target_source_language_column to save payload. @RATIONALE The model's loadJob() method was incomplete — it only loaded targetColumn but omitted the other three target mapping fields. Save payload also omitted target_source_language_column. Verification: browser reconfirmed — all 4 target columns pre-filled with saved values after reload.
This commit is contained in:
@@ -10,11 +10,17 @@
|
||||
// @RELATION DEPENDS_ON -> [api]
|
||||
// @RELATION CALLS -> [log]
|
||||
// @INVARIANT DECOMPOSITION GATE: 50+ atoms, ~400 lines. Model serves as single source of truth for all form state.
|
||||
// @RATIONALE Methods are NOT arrow class fields — they rely on `this` to mutate state. When passed as props
|
||||
// to child components (e.g. onTriggerRun={m.handleTriggerRun}), the binding is lost and `this`
|
||||
// becomes `undefined`, throwing "Cannot set properties of undefined". Consumers MUST wrap
|
||||
// in arrow functions: onTriggerRun={(full) => m.handleTriggerRun(full)}.
|
||||
// @REJECTED Converting methods to arrow class fields rejected — it would conflict with the Svelte 5
|
||||
// `$state` rune initialization order for non-primitive state atoms in the constructor.
|
||||
import { api } from '$lib/api.js';
|
||||
import { log } from '$lib/cot-logger';
|
||||
import { addToast } from '$lib/toasts.svelte.js';
|
||||
import { _, getT } from '$lib/i18n/index.svelte.js';
|
||||
import { triggerRun, fetchRunHistory, cancelRun } from '$lib/api/translate.js';
|
||||
import { triggerRun, fetchRunHistory, cancelRun, fetchDatasourceColumns } from '$lib/api/translate.js';
|
||||
import { startTranslationRun, resetTranslationRun, translationRunStore } from '$lib/stores/translationRun.svelte.js';
|
||||
|
||||
type UxState = 'idle' | 'loading' | 'configured' | 'saving' | 'validation_error' | 'datasource_unavailable';
|
||||
@@ -172,10 +178,16 @@ export class TranslationJobModel {
|
||||
this.uxState = 'loading';
|
||||
try {
|
||||
const [providers, dicts] = await Promise.all([
|
||||
api.requestApi('/translate/llm-providers').catch(() => []),
|
||||
api.requestApi<unknown>('/llm/providers').catch(() => ({ providers: [] })),
|
||||
api.requestApi('/translate/dictionaries?page_size=100').catch(() => ({ items: [] })),
|
||||
]);
|
||||
this.llmProviders = (Array.isArray(providers) ? providers : (providers as { items?: unknown[] })?.items || []) as Record<string, unknown>[];
|
||||
this.llmProviders = (
|
||||
Array.isArray(providers)
|
||||
? providers
|
||||
: ((providers as { providers?: unknown[] })?.providers
|
||||
?? (providers as { results?: unknown[] })?.results
|
||||
?? [])
|
||||
) as Record<string, unknown>[];
|
||||
this.availableDictionaries = ((dicts as { items?: unknown[] })?.items || (dicts as { results?: unknown[] })?.results || []) as Record<string, unknown>[];
|
||||
|
||||
if (!this.isNewJob) {
|
||||
@@ -187,6 +199,9 @@ export class TranslationJobModel {
|
||||
this.sourceTable = (job.source_table as string) || '';
|
||||
this.translationColumn = (job.translation_column as string) || '';
|
||||
this.targetColumn = (job.target_column as string) || '';
|
||||
this.targetLanguageColumn = (job.target_language_column as string) || '';
|
||||
this.targetSourceColumn = (job.target_source_column as string) || '';
|
||||
this.targetSourceLanguageColumn = (job.target_source_language_column as string) || '';
|
||||
this.targetLanguages = (job.target_languages as string[]) || ['en'];
|
||||
this.providerId = (job.provider_id as string) || '';
|
||||
this.batchSize = (job.batch_size as number) || 50;
|
||||
@@ -225,9 +240,9 @@ export class TranslationJobModel {
|
||||
async loadDatasourceColumns(): Promise<void> {
|
||||
if (!this.datasourceId) return;
|
||||
try {
|
||||
const res = await api.requestApi(`/translate/datasources/${this.datasourceId}/columns`) as { columns?: Record<string, unknown>[]; virtual?: Record<string, unknown>[] };
|
||||
this.availableColumns = (res.columns || []) as Record<string, unknown>[];
|
||||
this.virtualColumns = (res.virtual || []) as Record<string, unknown>[];
|
||||
const res = await fetchDatasourceColumns<{ columns?: Record<string, unknown>[]; virtual?: Record<string, unknown>[] }>(this.datasourceId, this.environmentId);
|
||||
this.availableColumns = (res?.columns || []) as Record<string, unknown>[];
|
||||
this.virtualColumns = (res?.virtual || []) as Record<string, unknown>[];
|
||||
} catch { this.availableColumns = []; this.virtualColumns = []; }
|
||||
}
|
||||
|
||||
@@ -264,11 +279,12 @@ export class TranslationJobModel {
|
||||
environment_id: this.environmentId || undefined,
|
||||
target_language_column: this.targetLanguageColumn || undefined,
|
||||
target_source_column: this.targetSourceColumn || undefined,
|
||||
target_source_language_column: this.targetSourceLanguageColumn || undefined,
|
||||
status: this.status,
|
||||
};
|
||||
const url = this.isNewJob ? '/translate/jobs' : `/translate/jobs/${this.jobId}`;
|
||||
const method = this.isNewJob ? 'POST' : 'PUT';
|
||||
const resp = await api.requestApi(url, { method, body: payload }) as { id?: string };
|
||||
const method: string = this.isNewJob ? 'POST' : 'PUT';
|
||||
const resp = await api.requestApi<{ id?: string }>(url, method, payload);
|
||||
if (resp?.id && this.isNewJob) {
|
||||
this.jobId = resp.id;
|
||||
this.isNewJob = false;
|
||||
|
||||
Reference in New Issue
Block a user