i18 cleanup

This commit is contained in:
2026-02-25 18:31:50 +03:00
parent 31cdc7958d
commit 31341d083f
48 changed files with 1431 additions and 808 deletions

View File

@@ -312,7 +312,7 @@
<!-- Pagination Controls -->
<div class="flex items-center justify-between mt-6">
<div class="text-sm text-gray-500">
{($t.dashboard?.showing || "")
{($t.dashboard?.showing )
.replace("{start}", (currentPage * pageSize + 1).toString())
.replace(
"{end}",

View File

@@ -49,7 +49,7 @@
value={selectedId}
on:change={handleSelect}
>
<option value="" disabled>{$t.common?.choose_environment || "-- Choose an environment --"}</option>
<option value="" disabled>{$t.common?.choose_environment}</option>
{#each environments as env}
<option value={env.id}>{env.name} ({env.url})</option>
{/each}

View File

@@ -11,6 +11,7 @@
<script lang="ts">
// [SECTION: IMPORTS]
import { createEventDispatcher } from 'svelte';
import { t } from '$lib/i18n';
// [/SECTION]
// [SECTION: PROPS]
@@ -62,9 +63,9 @@
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source Database</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Target Database</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.dashboard?.source_database }</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.dashboard?.target_database }</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.dashboard?.status }</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@@ -81,7 +82,7 @@
value={mapping?.target_db_uuid || suggestion?.target_db_uuid || ""}
on:change={(e) => updateMapping(sDb.uuid, (e.target as HTMLSelectElement).value)}
>
<option value="">-- Select Target --</option>
<option value="">{$t.migration?.target_env }</option>
{#each targetDatabases as tDb}
<option value={tDb.uuid}>{tDb.database_name}</option>
{/each}
@@ -89,11 +90,11 @@
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{#if mapping}
<span class="text-blue-600 font-semibold">Saved</span>
<span class="text-blue-600 font-semibold">{$t.dashboard?.saved }</span>
{:else if suggestion}
<span class="text-green-600 font-semibold">Suggested ({Math.round(suggestion.confidence * 100)}%)</span>
<span class="text-green-600 font-semibold">{$t.dashboard?.suggested } ({Math.round(suggestion.confidence * 100)}%)</span>
{:else}
<span class="text-red-600">Unmapped</span>
<span class="text-red-600">{$t.dashboard?.not_mapped }</span>
{/if}
</td>
</tr>

View File

@@ -10,6 +10,7 @@
import { onMount, onDestroy } from 'svelte';
import { selectedTask } from '../lib/stores.js';
import { api } from '../lib/api.js';
import { t } from '../lib/i18n';
let tasks = [];
let loading = true;
@@ -51,7 +52,7 @@
// @PRE: User confirms deletion via prompt.
// @POST: Tasks are deleted from backend and list is re-fetched.
async function clearTasks(status = null) {
if (!confirm('Are you sure you want to clear tasks?')) return;
if (!confirm($t.tasks?.clear_confirm )) return;
try {
let endpoint = '/tasks';
if (status) endpoint += `?status=${status}`;
@@ -74,7 +75,7 @@
const fullTask = await api.getTask(task.id);
selectedTask.set(fullTask);
} catch (e) {
console.error("Failed to fetch full task details:", e);
console.error($t.tasks?.fetch_task_details_failed , e);
selectedTask.set(task);
}
}
@@ -119,21 +120,21 @@
<div class="bg-white shadow overflow-hidden sm:rounded-lg mb-8">
<div class="px-4 py-5 sm:px-6 flex justify-between items-center">
<h3 class="text-lg leading-6 font-medium text-gray-900">
Recent Tasks
{$t.tasks?.recent }
</h3>
<div class="flex space-x-4 items-center">
<div class="relative inline-block text-left group">
<button class="text-sm text-red-600 hover:text-red-900 focus:outline-none flex items-center py-2">
Clear Tasks
{$t.tasks?.clear_tasks }
<svg class="ml-1 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<!-- Added a transparent bridge to prevent menu closing when moving cursor -->
<div class="absolute h-2 w-full top-full left-0"></div>
<div class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none hidden group-hover:block z-50">
<div class="py-1">
<button on:click={() => clearTasks()} class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Clear All Non-Running</button>
<button on:click={() => clearTasks('FAILED')} class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Clear Failed</button>
<button on:click={() => clearTasks('AWAITING_INPUT')} class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Clear Awaiting Input</button>
<button on:click={() => clearTasks()} class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">{$t.tasks?.clear_non_running }</button>
<button on:click={() => clearTasks('FAILED')} class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">{$t.tasks?.clear_failed }</button>
<button on:click={() => clearTasks('AWAITING_INPUT')} class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">{$t.tasks?.clear_awaiting_input }</button>
</div>
</div>
</div>
@@ -141,17 +142,17 @@
on:click={fetchTasks}
class="text-sm text-indigo-600 hover:text-indigo-900 focus:outline-none"
>
Refresh
{$t.common?.refresh }
</button>
</div>
</div>
{#if loading && tasks.length === 0}
<div class="p-4 text-center text-gray-500">Loading tasks...</div>
<div class="p-4 text-center text-gray-500">{$t.tasks?.loading }</div>
{:else if error}
<div class="p-4 text-center text-red-500">{error}</div>
{:else if tasks.length === 0}
<div class="p-4 text-center text-gray-500">No recent tasks found.</div>
<div class="p-4 text-center text-gray-500">{$t.tasks?.no_tasks }</div>
{:else}
<ul class="divide-y divide-gray-200">
{#each tasks as task}
@@ -179,13 +180,13 @@
{#if task.params.from_env && task.params.to_env}
{task.params.from_env} &rarr; {task.params.to_env}
{:else}
Params: {Object.keys(task.params).length} keys
{$t.tasks?.parameters }: {Object.keys(task.params).length} {$t.tasks?.keys }
{/if}
</p>
</div>
<div class="mt-2 flex items-center text-sm text-gray-500 sm:mt-0">
<p>
Started: {new Date(task.started_at || task.created_at || Date.now()).toLocaleString()}
{$t.tasks?.started_label }: {new Date(task.started_at || task.created_at || Date.now()).toLocaleString()}
</p>
</div>
</div>
@@ -196,4 +197,4 @@
</ul>
{/if}
</div>
<!-- [/DEF:TaskHistory:Component] -->
<!-- [/DEF:TaskHistory:Component] -->

View File

@@ -63,9 +63,9 @@
<div class="bg-white shadow overflow-hidden sm:rounded-md">
{#if loading && tasks.length === 0}
<div class="p-4 text-center text-gray-500">{$t.tasks?.loading || 'Loading...'}</div>
<div class="p-4 text-center text-gray-500">{$t.tasks?.loading}</div>
{:else if tasks.length === 0}
<div class="p-4 text-center text-gray-500">{$t.tasks?.no_tasks || 'No tasks found.'}</div>
<div class="p-4 text-center text-gray-500">{$t.tasks?.no_tasks}</div>
{:else}
<ul class="divide-y divide-gray-200">
{#each tasks as task (task.id)}
@@ -99,7 +99,7 @@
<path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
</svg>
<p>
{($t.tasks?.started || "").replace('{time}', formatTime(task.started_at))}
{$t.tasks?.started?.replace('{time}', formatTime(task.started_at))}
</p>
</div>
</div>

View File

@@ -144,7 +144,7 @@
<div
class="w-5 h-5 border-2 border-terminal-border border-t-primary rounded-full animate-spin"
></div>
<span>{$t.tasks?.loading || "Loading logs..."}</span>
<span>{$t.tasks?.loading }</span>
</div>
{:else if error}
<div
@@ -154,7 +154,7 @@
<span>{error}</span>
<button
class="bg-terminal-surface text-terminal-text-subtle border border-terminal-border rounded-md px-3 py-1 text-xs cursor-pointer transition-all hover:bg-terminal-border hover:text-terminal-text-bright"
onclick={handleRefresh}>Retry</button
onclick={handleRefresh}>{$t.common?.retry }</button
>
</div>
{:else}
@@ -203,7 +203,7 @@
class="text-lg font-medium text-gray-100"
id="modal-title"
>
{$t.tasks?.logs_title || "Task Logs"}
{$t.tasks?.logs_title }
</h3>
<button
class="text-gray-500 hover:text-gray-300"
@@ -211,13 +211,13 @@
show = false;
dispatch("close");
}}
aria-label="Close"></button
aria-label={$t.common?.close }></button
>
</div>
<div class="h-[500px]">
{#if loading && logs.length === 0}
<p class="text-gray-500 text-center">
{$t.tasks?.loading || "Loading..."}
{$t.tasks?.loading }
</p>
{:else if error}
<p class="text-red-400 text-center">{error}</p>

View File

@@ -15,7 +15,8 @@
import { addToast } from '../lib/toasts.js';
import MissingMappingModal from './MissingMappingModal.svelte';
import PasswordPrompt from './PasswordPrompt.svelte';
import TaskLogPanel from './tasks/TaskLogPanel.svelte';
import TaskLogPanel from './tasks/TaskLogPanel.svelte';
import { t } from '../lib/i18n';
// [/SECTION]
let ws;
@@ -135,7 +136,7 @@
}, delay);
} else if (reconnectAttempts >= maxReconnectAttempts) {
console.error('[TaskRunner][Coherence:Failed] Max reconnect attempts reached.');
addToast('Failed to connect to log stream after multiple attempts.', 'error');
addToast($t.tasks?.log_stream_failed, 'error');
}
};
}
@@ -219,10 +220,10 @@
});
connectionStatus = 'connected';
addToast('Mapping resolved, migration continuing...', 'success');
} catch (e) {
addToast('Failed to resolve mapping: ' + e.message, 'error');
}
addToast($t.tasks?.mapping_resolved, 'success');
} catch (e) {
addToast($t.tasks?.mapping_resolve_failed?.replace('{error}', e.message), 'error');
}
}
// [/DEF:handleMappingResolve:Function]
@@ -241,10 +242,10 @@
showPasswordPrompt = false;
connectionStatus = 'connected';
addToast('Passwords submitted, resuming migration...', 'success');
} catch (e) {
addToast('Failed to resume task: ' + e.message, 'error');
}
addToast($t.tasks?.passwords_submitted, 'success');
} catch (e) {
addToast($t.tasks?.resume_failed?.replace('{error}', e.message), 'error');
}
}
// [/DEF:handlePasswordResume:Function]
@@ -322,29 +323,29 @@
<div class="p-4 border rounded-lg bg-white shadow-md">
{#if $selectedTask}
<div class="flex justify-between items-center mb-2">
<h2 class="text-xl font-semibold">Task: {$selectedTask.plugin_id}</h2>
<h2 class="text-xl font-semibold">{$t.tasks?.task_label}: {$selectedTask.plugin_id}</h2>
<div class="flex items-center space-x-2">
{#if connectionStatus === 'connecting'}
<span class="flex h-3 w-3 relative">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-yellow-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-yellow-500"></span>
</span>
<span class="text-xs text-gray-500">Connecting...</span>
<span class="text-xs text-gray-500">{$t.tasks?.connecting}</span>
{:else if connectionStatus === 'connected'}
<span class="h-3 w-3 rounded-full bg-green-500"></span>
<span class="text-xs text-gray-500">Live</span>
<span class="text-xs text-gray-500">{$t.tasks?.live}</span>
{:else if connectionStatus === 'completed'}
<span class="h-3 w-3 rounded-full bg-blue-500"></span>
<span class="text-xs text-gray-500">Completed</span>
<span class="text-xs text-gray-500">{$t.tasks?.completed}</span>
{:else if connectionStatus === 'awaiting_mapping'}
<span class="h-3 w-3 rounded-full bg-orange-500 animate-pulse"></span>
<span class="text-xs text-gray-500">Awaiting Mapping</span>
<span class="text-xs text-gray-500">{$t.tasks?.awaiting_mapping}</span>
{:else if connectionStatus === 'awaiting_input'}
<span class="h-3 w-3 rounded-full bg-orange-500 animate-pulse"></span>
<span class="text-xs text-gray-500">Awaiting Input</span>
<span class="text-xs text-gray-500">{$t.tasks?.awaiting_input}</span>
{:else}
<span class="h-3 w-3 rounded-full bg-red-500"></span>
<span class="text-xs text-gray-500">Disconnected</span>
<span class="text-xs text-gray-500">{$t.tasks?.disconnected}</span>
{/if}
</div>
</div>
@@ -352,16 +353,16 @@
<!-- Task Info Section -->
<div class="mb-4 bg-gray-50 p-3 rounded text-sm border border-gray-200">
<details open>
<summary class="cursor-pointer font-medium text-gray-700 focus:outline-none hover:text-indigo-600">Task Details & Parameters</summary>
<summary class="cursor-pointer font-medium text-gray-700 focus:outline-none hover:text-indigo-600">{$t.tasks?.details_parameters}</summary>
<div class="mt-2 pl-2 border-l-2 border-indigo-200">
<div class="grid grid-cols-2 gap-2 mb-2">
<div><span class="font-semibold">ID:</span> <span class="text-gray-600">{$selectedTask.id}</span></div>
<div><span class="font-semibold">Status:</span> <span class="text-gray-600">{$selectedTask.status}</span></div>
<div><span class="font-semibold">Started:</span> <span class="text-gray-600">{new Date($selectedTask.started_at || $selectedTask.created_at || Date.now()).toLocaleString()}</span></div>
<div><span class="font-semibold">Plugin:</span> <span class="text-gray-600">{$selectedTask.plugin_id}</span></div>
<div><span class="font-semibold">{$t.common?.id}:</span> <span class="text-gray-600">{$selectedTask.id}</span></div>
<div><span class="font-semibold">{$t.dashboard?.status}:</span> <span class="text-gray-600">{$selectedTask.status}</span></div>
<div><span class="font-semibold">{$t.tasks?.started_label}:</span> <span class="text-gray-600">{new Date($selectedTask.started_at || $selectedTask.created_at || Date.now()).toLocaleString()}</span></div>
<div><span class="font-semibold">{$t.tasks?.plugin}:</span> <span class="text-gray-600">{$selectedTask.plugin_id}</span></div>
</div>
<div class="mt-1">
<span class="font-semibold">Parameters:</span>
<span class="font-semibold">{$t.tasks?.parameters}:</span>
<pre class="text-xs bg-gray-100 p-2 rounded mt-1 overflow-x-auto border border-gray-200">{JSON.stringify($selectedTask.params, null, 2)}</pre>
</div>
</div>
@@ -378,14 +379,14 @@
{#if waitingForData && connectionStatus === 'connected'}
<div class="text-gray-500 italic mt-2 animate-pulse text-xs">
Waiting for new logs...
</div>
{/if}
</div>
{:else}
<p>No task selected.</p>
{/if}
</div>
{$t.tasks?.waiting_logs}
</div>
{/if}
</div>
{:else}
<p>{$t.tasks?.select_task}</p>
{/if}
</div>
<MissingMappingModal
bind:show={showMappingModal}

View File

@@ -60,7 +60,7 @@
console.log(`[BranchSelector][Coherence:OK] Loaded ${branches.length} branches`);
} catch (e) {
console.error(`[BranchSelector][Coherence:Failed] ${e.message}`);
toast('Failed to load branches', 'error');
toast($t.git?.load_branches_failed, 'error');
} finally {
loading = false;
}
@@ -90,7 +90,7 @@
await gitService.checkoutBranch(dashboardId, branchName);
currentBranch = branchName;
dispatch('change', { branch: branchName });
toast(`Switched to ${branchName}`, 'success');
toast($t.git?.switched_to?.replace('{branch}', branchName), 'success');
console.log(`[BranchSelector][Coherence:OK] Checked out ${branchName}`);
} catch (e) {
console.error(`[BranchSelector][Coherence:Failed] ${e.message}`);
@@ -110,7 +110,7 @@
console.log(`[BranchSelector][Action] Creating branch ${newBranchName} from ${currentBranch}`);
try {
await gitService.createBranch(dashboardId, newBranchName, currentBranch);
toast(`Created branch ${newBranchName}`, 'success');
toast($t.git?.created_branch?.replace('{branch}', newBranchName), 'success');
showCreate = false;
newBranchName = '';
await loadBranches();
@@ -151,7 +151,7 @@
<div class="flex-grow">
<Input
bind:value={newBranchName}
placeholder="branch-name"
placeholder={$t.git?.branch_name_placeholder}
disabled={loading}
/>
</div>

View File

@@ -50,10 +50,10 @@
`/git/repositories/${dashboardId}/generate-message`,
);
message = data.message;
toast($t.git?.commit_message_generated || "Commit message generated", "success");
toast($t.git?.commit_message_generated, "success");
} catch (e) {
console.error(`[CommitModal][Coherence:Failed] ${e.message}`);
toast(e.message || ($t.git?.commit_message_failed || "Failed to generate message"), "error");
toast(e.message || $t.git?.commit_message_failed, "error");
} finally {
generatingMessage = false;
}
@@ -94,7 +94,7 @@
if (!diff) diff = "";
} catch (e) {
console.error(`[CommitModal][Coherence:Failed] ${e.message}`);
toast($t.git?.load_changes_failed || "Failed to load changes", "error");
toast($t.git?.load_changes_failed, "error");
} finally {
loading = false;
}
@@ -115,7 +115,7 @@
committing = true;
try {
await gitService.commit(dashboardId, message, []);
toast($t.git?.commit_success || "Changes committed successfully", "success");
toast($t.git?.commit_success, "success");
dispatch("commit");
show = false;
message = "";
@@ -142,7 +142,7 @@
<div
class="bg-white p-6 rounded-lg shadow-xl w-full max-w-4xl max-h-[90vh] flex flex-col"
>
<h2 class="text-xl font-bold mb-4">{$t.git?.commit || "Commit Changes"}</h2>
<h2 class="text-xl font-bold mb-4">{$t.git?.commit}</h2>
<div class="flex flex-col md:flex-row gap-4 flex-1 overflow-hidden">
<!-- Left: Message and Files -->
@@ -151,7 +151,7 @@
<div class="flex justify-between items-center mb-1">
<label
class="block text-sm font-medium text-gray-700"
>{$t.git?.commit_message || "Commit Message"}</label
>{$t.git?.commit_message}</label
>
<button
onclick={handleGenerateMessage}
@@ -159,16 +159,16 @@
class="text-xs text-blue-600 hover:text-blue-800 disabled:opacity-50 flex items-center"
>
{#if generatingMessage}
<span class="animate-spin mr-1"></span> {$t.mapper?.generating || "Generating..."}
<span class="animate-spin mr-1"></span> {$t.mapper?.generating}
{:else}
<span class="mr-1"></span> {$t.git?.generate_with_ai || "Generate with AI"}
<span class="mr-1"></span> {$t.git?.generate_with_ai}
{/if}
</button>
</div>
<textarea
bind:value={message}
class="w-full border rounded p-2 h-32 focus:ring-2 focus:ring-blue-500 outline-none resize-none"
placeholder={$t.git?.describe_changes || "Describe your changes..."}
placeholder={$t.git?.describe_changes}
></textarea>
</div>
@@ -177,13 +177,13 @@
<h3
class="text-sm font-bold text-gray-500 uppercase mb-2"
>
{$t.git?.changed_files || "Changed Files"}
{$t.git?.changed_files}
</h3>
<ul class="text-xs space-y-1">
{#each status.staged_files as file}
<li
class="text-green-600 flex items-center font-semibold"
title="Staged"
title={$t.git?.staged}
>
<span class="mr-2">S</span>
{file}
@@ -192,7 +192,7 @@
{#each status.modified_files as file}
<li
class="text-yellow-600 flex items-center"
title="Modified (Unstaged)"
title={$t.git?.modified_unstaged}
>
<span class="mr-2">M</span>
{file}
@@ -201,7 +201,7 @@
{#each status.untracked_files as file}
<li
class="text-blue-600 flex items-center"
title="Untracked"
title={$t.git?.untracked}
>
<span class="mr-2">?</span>
{file}
@@ -219,14 +219,14 @@
<div
class="bg-gray-200 px-3 py-1 text-xs font-bold text-gray-600 border-b"
>
{$t.git?.changes_preview || "Changes Preview"}
{$t.git?.changes_preview}
</div>
<div class="flex-1 overflow-auto p-2">
{#if loading}
<div
class="flex items-center justify-center h-full text-gray-500"
>
{$t.git?.loading_diff || "Loading diff..."}
{$t.git?.loading_diff}
</div>
{:else if diff}
<pre
@@ -235,7 +235,7 @@
<div
class="flex items-center justify-center h-full text-gray-500 italic"
>
{$t.git?.no_changes || "No changes detected"}
{$t.git?.no_changes}
</div>
{/if}
</div>
@@ -247,7 +247,7 @@
onclick={() => (show = false)}
class="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded"
>
{$t.common?.cancel || "Cancel"}
{$t.common?.cancel}
</button>
<button
onclick={handleCommit}
@@ -258,7 +258,7 @@
status?.staged_files?.length === 0)}
class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50"
>
{committing ? ($t.git?.committing || "Committing...") : ($t.git?.commit || "Commit")}
{committing ? $t.git?.committing : $t.git?.commit}
</button>
</div>
</div>

View File

@@ -56,7 +56,7 @@
);
} catch (e) {
console.error(`[DeploymentModal][Coherence:Failed] ${e.message}`);
toast($t.migration?.loading_envs_failed || "Failed to load environments", "error");
toast($t.migration?.loading_envs_failed, "error");
} finally {
loading = false;
}
@@ -77,7 +77,7 @@
try {
const result = await gitService.deploy(dashboardId, selectedEnv);
toast(
result.message || ($t.git?.deploy_success || "Deployment triggered successfully"),
result.message || $t.git?.deploy_success,
"success",
);
dispatch("deploy");
@@ -99,26 +99,26 @@
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
>
<div class="bg-white p-6 rounded-lg shadow-xl w-96">
<h2 class="text-xl font-bold mb-4">{$t.git?.deploy || "Deploy Dashboard"}</h2>
<h2 class="text-xl font-bold mb-4">{$t.git?.deploy}</h2>
{#if loading}
<p class="text-gray-500">{$t.migration?.loading_envs || "Loading environments..."}</p>
<p class="text-gray-500">{$t.migration?.loading_envs}</p>
{:else if environments.length === 0}
<p class="text-red-500 mb-4">
{$t.git?.no_deploy_envs || "No deployment environments configured."}
{$t.git?.no_deploy_envs}
</p>
<div class="flex justify-end">
<button
onclick={() => (show = false)}
class="px-4 py-2 bg-gray-200 text-gray-800 rounded hover:bg-gray-300"
>
{$t.common?.close || "Close"}
{$t.common?.close}
</button>
</div>
{:else}
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2"
>{$t.migration?.target_env || "Select Target Environment"}</label
>{$t.migration?.target_env}</label
>
<select
bind:value={selectedEnv}
@@ -137,7 +137,7 @@
onclick={() => (show = false)}
class="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded"
>
{$t.common?.cancel || "Cancel"}
{$t.common?.cancel}
</button>
<button
onclick={handleDeploy}
@@ -165,9 +165,9 @@
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
{$t.git?.deploying || "Deploying..."}
{$t.git?.deploying}
{:else}
{$t.git?.deploy || "Deploy"}
{$t.git?.deploy}
{/if}
</button>
</div>

View File

@@ -82,13 +82,13 @@
*/
async function handleInit() {
if (!selectedConfigId || !remoteUrl) {
toast($t.git?.init_validation_error || 'Please select a Git server and provide remote URL', 'error');
toast($t.git?.init_validation_error, 'error');
return;
}
loading = true;
try {
await gitService.initRepository(dashboardId, selectedConfigId, remoteUrl);
toast($t.git?.init_success || 'Repository initialized successfully', 'success');
toast($t.git?.init_success, 'success');
initialized = true;
} catch (e) {
toast(e.message, 'error');
@@ -110,7 +110,7 @@
// Try to get selected environment from localStorage (set by EnvSelector)
const sourceEnvId = localStorage.getItem('selected_env_id');
await gitService.sync(dashboardId, sourceEnvId);
toast($t.git?.sync_success || 'Dashboard state synced to Git', 'success');
toast($t.git?.sync_success, 'success');
} catch (e) {
toast(e.message, 'error');
} finally {
@@ -129,7 +129,7 @@
loading = true;
try {
await gitService.push(dashboardId);
toast($t.git?.push_success || 'Changes pushed to remote', 'success');
toast($t.git?.push_success, 'success');
} catch (e) {
toast(e.message, 'error');
} finally {
@@ -148,7 +148,7 @@
loading = true;
try {
await gitService.pull(dashboardId);
toast($t.git?.pull_success || 'Changes pulled from remote', 'success');
toast($t.git?.pull_success, 'success');
} catch (e) {
toast(e.message, 'error');
} finally {
@@ -164,8 +164,8 @@
{#if show}
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white p-6 rounded-lg shadow-2xl w-full max-w-4xl max-h-[90vh] overflow-y-auto">
<PageHeader title={`${$t.git?.management || "Git Management"}: ${dashboardTitle}`}>
<div slot="subtitle" class="text-sm text-gray-500">{$t.common?.id || "ID"}: {dashboardId}</div>
<PageHeader title={`${$t.git?.management}: ${dashboardTitle}`}>
<div slot="subtitle" class="text-sm text-gray-500">{$t.common?.id}: {dashboardId}</div>
<div slot="actions">
<button onclick={() => show = false} class="text-gray-400 hover:text-gray-600 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -193,13 +193,13 @@
options={configs.map(c => ({ value: c.id, label: `${c.name} (${c.provider})` }))}
/>
{#if configs.length === 0}
<p class="text-xs text-red-500 -mt-4">{$t.git?.no_servers_configured || "No Git servers configured. Go to Settings -> Git to add one."}</p>
<p class="text-xs text-red-500 -mt-4">{$t.git?.no_servers_configured}</p>
{/if}
<Input
label={$t.git.remote_url}
bind:value={remoteUrl}
placeholder={$t.git?.remote_url_placeholder || "https://github.com/org/repo.git"}
placeholder={$t.git?.remote_url_placeholder}
/>
<Button

View File

@@ -313,8 +313,8 @@
class={`text-xs px-2 py-0.5 rounded-full ${isMultimodalModel(provider.default_model) ? "bg-sky-100 text-sky-800" : "bg-amber-100 text-amber-800"}`}
>
{isMultimodalModel(provider.default_model)
? ($t.llm?.multimodal || "Multimodal")
: ($t.llm?.text_only || "Text only")}
? ($t.llm?.multimodal )
: ($t.llm?.text_only )}
</span>
</div>
<div class="text-sm text-gray-500">

View File

@@ -3,6 +3,7 @@
<!-- @PURPOSE: Displays the results of an LLM-based dashboard validation task. -->
<script>
import { t } from '$lib/i18n';
let {
report,
} = $props();
@@ -21,27 +22,27 @@
{#if result}
<div class="bg-white shadow rounded-lg p-6 space-y-6">
<div class="flex items-center justify-between">
<h2 class="text-xl font-bold text-gray-900">Validation Report</h2>
<h2 class="text-xl font-bold text-gray-900">{$t.llm?.validation_report_title}</h2>
<span class={`px-3 py-1 rounded-full text-sm font-medium ${getStatusColor(result.status)}`}>
{result.status}
</span>
</div>
<div class="prose max-w-none">
<h3 class="text-lg font-semibold">Summary</h3>
<h3 class="text-lg font-semibold">{$t.reports?.summary}</h3>
<p>{result.summary}</p>
</div>
{#if result.issues && result.issues.length > 0}
<div class="space-y-4">
<h3 class="text-lg font-semibold">Detected Issues</h3>
<h3 class="text-lg font-semibold">{$t.tasks?.issues}</h3>
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900">Severity</th>
<th class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Message</th>
<th class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Location</th>
<th class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900">{$t.reports?.severity}</th>
<th class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">{$t.reports?.message}</th>
<th class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">{$t.tasks?.location}</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
@@ -53,7 +54,7 @@
</span>
</td>
<td class="px-3 py-4 text-sm text-gray-500">{issue.message}</td>
<td class="px-3 py-4 text-sm text-gray-500">{issue.location || 'N/A'}</td>
<td class="px-3 py-4 text-sm text-gray-500">{issue.location || $t.common?.not_available}</td>
</tr>
{/each}
</tbody>
@@ -64,15 +65,15 @@
{#if result.screenshot_path}
<div class="space-y-4">
<h3 class="text-lg font-semibold">Screenshot</h3>
<img src={`/api/storage/file?path=${encodeURIComponent(result.screenshot_path)}`} alt="Dashboard Screenshot" class="rounded-lg border border-gray-200 shadow-sm max-w-full" />
<h3 class="text-lg font-semibold">{$t.dashboard?.screenshot_strategy}</h3>
<img src={`/api/storage/file?path=${encodeURIComponent(result.screenshot_path)}`} alt={$t.dashboard?.dashboard_validation} class="rounded-lg border border-gray-200 shadow-sm max-w-full" />
</div>
{/if}
</div>
{:else}
<div class="text-center py-12 bg-gray-50 rounded-lg border-2 border-dashed border-gray-300">
<p class="text-gray-500">No validation result available.</p>
<p class="text-gray-500">{$t.llm?.no_validation_result}</p>
</div>
{/if}
<!-- [/DEF:frontend/src/components/llm/ValidationReport.svelte] -->
<!-- [/DEF:frontend/src/components/llm/ValidationReport.svelte] -->

View File

@@ -1,4 +1,5 @@
<script>
import { t } from '$lib/i18n';
let { task = null } = $props();
const result = $derived(task?.result || null);
@@ -23,22 +24,22 @@
{#if !task}
<div class="rounded-lg border border-dashed border-slate-200 bg-slate-50 p-6 text-sm text-slate-500">
Выберите задачу, чтобы увидеть результат.
{$t.tasks?.result_select_task}
</div>
{:else if !result}
<div class="rounded-lg border border-slate-200 bg-white p-4">
<p class="text-sm text-slate-700">Для этой задачи нет структурированного результата.</p>
<p class="text-sm text-slate-700">{$t.tasks?.result_not_structured}</p>
</div>
{:else if pluginId === 'llm_dashboard_validation'}
<div class="space-y-4 rounded-lg border border-slate-200 bg-white p-4">
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-slate-900">LLM проверка дашборда</h3>
<h3 class="text-sm font-semibold text-slate-900">{$t.tasks?.result_llm_validation}</h3>
<span class={`rounded-full px-2 py-1 text-xs font-semibold ${statusColor(result.status)}`}>{result.status || 'UNKNOWN'}</span>
</div>
<p class="text-sm text-slate-700">{result.summary || 'Нет summary'}</p>
<p class="text-sm text-slate-700">{result.summary || $t.tasks?.result_no_summary}</p>
{#if result.issues?.length}
<div>
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">Проблемы ({result.issues.length})</p>
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">{$t.tasks?.issues} ({result.issues.length})</p>
<ul class="space-y-2">
{#each result.issues as issue}
<li class="rounded-md border border-slate-200 bg-slate-50 p-2 text-sm">
@@ -47,7 +48,7 @@
<span class="text-slate-700">{issue.message}</span>
</div>
{#if issue.location}
<p class="mt-1 text-xs text-slate-500">Локация: {issue.location}</p>
<p class="mt-1 text-xs text-slate-500">{$t.tasks?.location}: {issue.location}</p>
{/if}
</li>
{/each}
@@ -58,18 +59,18 @@
{:else if pluginId === 'superset-backup'}
<div class="space-y-4 rounded-lg border border-slate-200 bg-white p-4">
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-slate-900">Результат бэкапа</h3>
<h3 class="text-sm font-semibold text-slate-900">{$t.tasks?.backup_result}</h3>
<span class={`rounded-full px-2 py-1 text-xs font-semibold ${statusColor(result.status)}`}>{result.status || 'UNKNOWN'}</span>
</div>
<div class="grid grid-cols-2 gap-2 text-sm text-slate-700">
<p>Environment: {result.environment || '-'}</p>
<p>Total: {result.total_dashboards ?? 0}</p>
<p>Успешно: {result.backed_up_dashboards ?? 0}</p>
<p>Ошибок: {result.failed_dashboards ?? 0}</p>
<p>{$t.dashboard?.environment}: {result.environment || $t.common?.not_available}</p>
<p>{$t.tasks?.total}: {result.total_dashboards ?? 0}</p>
<p>{$t.tasks?.successful}: {result.backed_up_dashboards ?? 0}</p>
<p>{$t.tasks?.failed}: {result.failed_dashboards ?? 0}</p>
</div>
{#if result.failures?.length}
<div>
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">Ошибки</p>
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">{$t.tasks?.errors}</p>
<ul class="space-y-2">
{#each result.failures as failure}
<li class="rounded-md border border-red-200 bg-red-50 p-2 text-sm text-red-700">
@@ -83,20 +84,20 @@
{:else if pluginId === 'superset-migration'}
<div class="space-y-4 rounded-lg border border-slate-200 bg-white p-4">
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-slate-900">Результат миграции</h3>
<h3 class="text-sm font-semibold text-slate-900">{$t.tasks?.migration_result}</h3>
<span class={`rounded-full px-2 py-1 text-xs font-semibold ${statusColor(result.status)}`}>{result.status || 'UNKNOWN'}</span>
</div>
<div class="grid grid-cols-2 gap-2 text-sm text-slate-700">
<p>Source: {result.source_environment || '-'}</p>
<p>Target: {result.target_environment || '-'}</p>
<p>Выбрано: {result.selected_dashboards ?? 0}</p>
<p>Успешно: {result.migrated_dashboards?.length ?? 0}</p>
<p>С ошибками: {result.failed_dashboards?.length ?? 0}</p>
<p>Mappings: {result.mapping_count ?? 0}</p>
<p>{$t.migration?.source_env}: {result.source_environment || $t.common?.not_available}</p>
<p>{$t.migration?.target_env}: {result.target_environment || $t.common?.not_available}</p>
<p>{$t.tasks?.selected}: {result.selected_dashboards ?? 0}</p>
<p>{$t.tasks?.successful}: {result.migrated_dashboards?.length ?? 0}</p>
<p>{$t.tasks?.with_errors}: {result.failed_dashboards?.length ?? 0}</p>
<p>{$t.tasks?.mappings}: {result.mapping_count ?? 0}</p>
</div>
{#if result.failed_dashboards?.length}
<div>
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">Ошибки миграции</p>
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">{$t.tasks?.migration_errors}</p>
<ul class="space-y-2">
{#each result.failed_dashboards as failed}
<li class="rounded-md border border-red-200 bg-red-50 p-2 text-sm text-red-700">

View File

@@ -31,7 +31,7 @@
// @POST: A new connection is created via the connection service and a success event is dispatched.
async function handleSubmit() {
if (!name || !host || !database || !username || !password) {
addToast($t.connections?.required_fields || 'Please fill in all required fields', 'warning');
addToast($t.connections?.required_fields, 'warning');
return;
}
@@ -40,7 +40,7 @@
const newConnection = await createConnection({
name, type, host, port: Number(port), database, username, password
});
addToast($t.connections?.created_success || 'Connection created successfully', 'success');
addToast($t.connections?.created_success, 'success');
dispatch('success', newConnection);
resetForm();
} catch (e) {
@@ -68,25 +68,25 @@
</script>
<!-- [SECTION: TEMPLATE] -->
<Card title={$t.connections?.add_new || "Add New Connection"}>
<Card title={$t.connections?.add_new}>
<form on:submit|preventDefault={handleSubmit} class="space-y-6">
<Input label={$t.connections?.name || "Connection Name"} bind:value={name} placeholder={$t.connections?.name_placeholder || "e.g. Production DWH"} />
<Input label={$t.connections?.name} bind:value={name} placeholder={$t.connections?.name_placeholder} />
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<Input label={$t.connections?.host || "Host"} bind:value={host} placeholder={$t.connections?.host_placeholder || "10.0.0.1"} />
<Input label={$t.connections?.port || "Port"} type="number" bind:value={port} />
<Input label={$t.connections?.host} bind:value={host} placeholder={$t.connections?.host_placeholder} />
<Input label={$t.connections?.port} type="number" bind:value={port} />
</div>
<Input label={$t.connections?.db_name || "Database Name"} bind:value={database} />
<Input label={$t.connections?.db_name} bind:value={database} />
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<Input label={$t.connections?.user || "Username"} bind:value={username} />
<Input label={$t.connections?.pass || "Password"} type="password" bind:value={password} />
<Input label={$t.connections?.user} bind:value={username} />
<Input label={$t.connections?.pass} type="password" bind:value={password} />
</div>
<div class="flex justify-end pt-2">
<Button type="submit" disabled={isSubmitting} isLoading={isSubmitting}>
{$t.connections?.create || "Create Connection"}
{$t.connections?.create}
</Button>
</div>
</form>

View File

@@ -28,7 +28,7 @@
try {
connections = await getConnections();
} catch (e) {
addToast($t.connections?.fetch_failed || 'Failed to fetch connections', 'error');
addToast($t.connections?.fetch_failed, 'error');
} finally {
isLoading = false;
}
@@ -40,11 +40,11 @@
// @PRE: id is provided and user confirms deletion.
// @POST: Connection is deleted from backend and list is reloaded.
async function handleDelete(id) {
if (!confirm($t.connections?.delete_confirm || 'Are you sure you want to delete this connection?')) return;
if (!confirm($t.connections?.delete_confirm)) return;
try {
await deleteConnection(id);
addToast($t.connections?.deleted_success || 'Connection deleted', 'success');
addToast($t.connections?.deleted_success, 'success');
await fetchConnections();
} catch (e) {
addToast(e.message, 'error');
@@ -59,12 +59,12 @@
</script>
<!-- [SECTION: TEMPLATE] -->
<Card title={$t.connections?.saved || "Saved Connections"} padding="none">
<Card title={$t.connections?.saved} padding="none">
<ul class="divide-y divide-gray-100">
{#if isLoading}
<li class="p-6 text-center text-gray-500">{$t.common.loading}</li>
{:else if connections.length === 0}
<li class="p-12 text-center text-gray-500 italic">{$t.connections?.no_saved || "No connections saved yet."}</li>
<li class="p-12 text-center text-gray-500 italic">{$t.connections?.no_saved}</li>
{:else}
{#each connections as conn}
<li class="p-6 flex items-center justify-between hover:bg-gray-50 transition-colors">
@@ -77,7 +77,7 @@
size="sm"
on:click={() => handleDelete(conn.id)}
>
{$t.connections?.delete || "Delete"}
{$t.connections?.delete}
</Button>
</li>
{/each}

View File

@@ -36,7 +36,7 @@
try {
envs = await api.getEnvironmentsList();
} catch (e) {
addToast($t.debug?.fetch_env_failed || 'Failed to fetch environments', 'error');
addToast($t.debug?.fetch_env_failed, 'error');
}
}
// [/DEF:fetchEnvironments:Function]
@@ -55,7 +55,7 @@
let params = { action };
if (action === 'test-db-api') {
if (!sourceEnv || !targetEnv) {
addToast($t.debug?.source_target_required || 'Source and Target environments are required', 'warning');
addToast($t.debug?.source_target_required, 'warning');
isRunning = false;
return;
}
@@ -65,7 +65,7 @@
params.target_env = tEnv.name;
} else {
if (!selectedEnv || !datasetId) {
addToast($t.debug?.env_dataset_required || 'Environment and Dataset ID are required', 'warning');
addToast($t.debug?.env_dataset_required, 'warning');
isRunning = false;
return;
}
@@ -102,11 +102,11 @@
clearInterval(pollInterval);
isRunning = false;
results = task.result;
addToast($t.debug?.completed || 'Debug task completed', 'success');
addToast($t.debug?.completed, 'success');
} else if (task.status === 'FAILED') {
clearInterval(pollInterval);
isRunning = false;
addToast($t.debug?.failed || 'Debug task failed', 'error');
addToast($t.debug?.failed, 'error');
}
} catch (e) {
clearInterval(pollInterval);
@@ -121,31 +121,31 @@
<div class="space-y-6">
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h3 class="text-lg font-medium text-gray-900 mb-4">{$t.debug?.title || 'System Diagnostics'}</h3>
<h3 class="text-lg font-medium text-gray-900 mb-4">{$t.debug?.title}</h3>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700">{$t.debug?.action || 'Debug Action'}</label>
<label class="block text-sm font-medium text-gray-700">{$t.debug?.action}</label>
<select bind:value={action} class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="test-db-api">{$t.debug?.test_db_api || 'Test Database API (Compare Envs)'}</option>
<option value="get-dataset-structure">{$t.debug?.get_dataset_structure || 'Get Dataset Structure (JSON)'}</option>
<option value="test-db-api">{$t.debug?.test_db_api}</option>
<option value="get-dataset-structure">{$t.debug?.get_dataset_structure}</option>
</select>
</div>
{#if action === 'test-db-api'}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="src-env" class="block text-sm font-medium text-gray-700">{$t.migration?.source_env || 'Source Environment'}</label>
<label for="src-env" class="block text-sm font-medium text-gray-700">{$t.migration?.source_env}</label>
<select id="src-env" bind:value={sourceEnv} class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="" disabled>{$t.debug?.select_source || '-- Select Source --'}</option>
<option value="" disabled>{$t.debug?.select_source}</option>
{#each envs as env}
<option value={env.id}>{env.name}</option>
{/each}
</select>
</div>
<div>
<label for="tgt-env" class="block text-sm font-medium text-gray-700">{$t.migration?.target_env || 'Target Environment'}</label>
<label for="tgt-env" class="block text-sm font-medium text-gray-700">{$t.migration?.target_env}</label>
<select id="tgt-env" bind:value={targetEnv} class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="" disabled>{$t.debug?.select_target || '-- Select Target --'}</option>
<option value="" disabled>{$t.debug?.select_target}</option>
{#each envs as env}
<option value={env.id}>{env.name}</option>
{/each}
@@ -155,16 +155,16 @@
{:else}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="debug-env" class="block text-sm font-medium text-gray-700">{$t.dashboard?.environment || 'Environment'}</label>
<label for="debug-env" class="block text-sm font-medium text-gray-700">{$t.dashboard?.environment}</label>
<select id="debug-env" bind:value={selectedEnv} class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="" disabled>{$t.common?.choose_environment || '-- Select Environment --'}</option>
<option value="" disabled>{$t.common?.choose_environment}</option>
{#each envs as env}
<option value={env.id}>{env.name}</option>
{/each}
</select>
</div>
<div>
<label for="debug-ds-id" class="block text-sm font-medium text-gray-700">{$t.mapper?.dataset_id || 'Dataset ID'}</label>
<label for="debug-ds-id" class="block text-sm font-medium text-gray-700">{$t.mapper?.dataset_id}</label>
<input type="number" id="debug-ds-id" bind:value={datasetId} class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" />
</div>
</div>
@@ -172,7 +172,7 @@
<div class="mt-4 flex justify-end">
<button on:click={handleRunDebug} disabled={isRunning} class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50">
{isRunning ? ($t.dashboard?.running || 'Running...') : ($t.debug?.run || 'Run Diagnostics')}
{isRunning ? $t.dashboard?.running : $t.debug?.run}
</button>
</div>
</div>
@@ -180,7 +180,7 @@
{#if results}
<div class="bg-white shadow overflow-hidden sm:rounded-md border border-gray-200">
<div class="px-4 py-5 sm:px-6 bg-gray-50 border-b border-gray-200">
<h3 class="text-lg leading-6 font-medium text-gray-900">{$t.debug?.output || 'Debug Output'}</h3>
<h3 class="text-lg leading-6 font-medium text-gray-900">{$t.debug?.output}</h3>
</div>
<div class="p-4">
<pre class="text-xs text-gray-600 bg-gray-900 text-green-400 p-4 rounded-md overflow-x-auto h-96">{JSON.stringify(results, null, 2)}</pre>

View File

@@ -106,7 +106,7 @@
const activeProvider = providers.find(p => p.is_active);
if (!activeProvider) {
addToast($t.mapper?.errors?.no_active_llm_provider || 'No active LLM provider found', 'error');
addToast($t.mapper?.errors?.no_active_llm_provider, 'error');
return;
}
@@ -117,9 +117,9 @@
});
selectedTask.set(task);
addToast($t.mapper?.success?.docs_started || 'Documentation generation started', 'success');
addToast($t.mapper?.success?.docs_started, 'success');
} catch (e) {
addToast(e.message || $t.mapper?.errors?.docs_start_failed || 'Failed to start documentation generation', 'error');
addToast(e.message || $t.mapper?.errors?.docs_start_failed, 'error');
} finally {
isGeneratingDocs = false;
}
@@ -130,9 +130,9 @@
try {
await api.put(`/mappings/datasets/${datasetId}/metadata`, doc);
generatedDoc = null;
addToast($t.mapper?.success?.docs_applied || 'Documentation applied successfully', 'success');
addToast($t.mapper?.success?.docs_applied, 'success');
} catch (err) {
addToast(err.message || $t.mapper?.errors?.docs_apply_failed || 'Failed to apply documentation', 'error');
addToast(err.message || $t.mapper?.errors?.docs_apply_failed, 'error');
}
}
@@ -212,7 +212,7 @@
label={$t.mapper.excel_path}
type="text"
bind:value={excelPath}
placeholder={$t.mapper?.excel_placeholder || "/path/to/mapping.xlsx"}
placeholder={$t.mapper?.excel_placeholder}
/>
</div>
{/if}
@@ -224,9 +224,9 @@
disabled={isGeneratingDocs || isRunning}
>
{#if isGeneratingDocs}
<span class="animate-spin mr-1"></span> {$t.mapper?.generating || "Generating..."}
<span class="animate-spin mr-1"></span> {$t.mapper?.generating}
{:else}
<span class="mr-1"></span> {$t.datasets?.generate_docs || "Generate Docs"}
<span class="mr-1"></span> {$t.datasets?.generate_docs}
{/if}
</Button>
<Button