ready for test

This commit is contained in:
2026-02-25 13:35:09 +03:00
parent 21e969a769
commit 33433c3173
11 changed files with 994 additions and 351 deletions

View File

@@ -22,9 +22,9 @@
const DEFAULT_LLM_PROMPTS = {
dashboard_validation_prompt:
"Analyze the attached dashboard screenshot and the following execution logs for health and visual issues.\\n\\nLogs:\\n{logs}\\n\\nProvide the analysis in JSON format with the following structure:\\n{\\n \\\"status\\\": \\\"PASS\\\" | \\\"WARN\\\" | \\\"FAIL\\\",\\n \\\"summary\\\": \\\"Short summary of findings\\\",\\n \\\"issues\\\": [\\n {\\n \\\"severity\\\": \\\"WARN\\\" | \\\"FAIL\\\",\\n \\\"message\\\": \\\"Description of the issue\\\",\\n \\\"location\\\": \\\"Optional location info (e.g. chart name)\\\"\\n }\\n ]\\n}",
'Analyze the attached dashboard screenshot and the following execution logs for health and visual issues.\\n\\nLogs:\\n{logs}\\n\\nProvide the analysis in JSON format with the following structure:\\n{\\n \\"status\\": \\"PASS\\" | \\"WARN\\" | \\"FAIL\\",\\n \\"summary\\": \\"Short summary of findings\\",\\n \\"issues\\": [\\n {\\n \\"severity\\": \\"WARN\\" | \\"FAIL\\",\\n \\"message\\": \\"Description of the issue\\",\\n \\"location\\": \\"Optional location info (e.g. chart name)\\"\\n }\\n ]\\n}',
documentation_prompt:
"Generate professional documentation for the following dataset and its columns.\\nDataset: {dataset_name}\\nColumns: {columns_json}\\n\\nProvide the documentation in JSON format:\\n{\\n \\\"dataset_description\\\": \\\"General description of the dataset\\\",\\n \\\"column_descriptions\\\": [\\n {\\n \\\"name\\\": \\\"column_name\\\",\\n \\\"description\\\": \\\"Generated description\\\"\\n }\\n ]\\n}",
'Generate professional documentation for the following dataset and its columns.\\nDataset: {dataset_name}\\nColumns: {columns_json}\\n\\nProvide the documentation in JSON format:\\n{\\n \\"dataset_description\\": \\"General description of the dataset\\",\\n \\"column_descriptions\\": [\\n {\\n \\"name\\": \\"column_name\\",\\n \\"description\\": \\"Generated description\\"\\n }\\n ]\\n}',
git_commit_prompt:
"Generate a concise and professional git commit message based on the following diff and recent history.\\nUse Conventional Commits format (e.g., feat: ..., fix: ..., docs: ...).\\n\\nRecent History:\\n{history}\\n\\nDiff:\\n{diff}\\n\\nCommit Message:",
};
@@ -59,6 +59,7 @@
// Load settings on mount
onMount(async () => {
await loadSettings();
await loadMigrationSettings();
});
// Load consolidated settings from API
@@ -95,7 +96,8 @@
...DEFAULT_LLM_PROVIDER_BINDINGS,
...(llm?.provider_bindings || {}),
};
normalized.assistant_planner_provider = llm?.assistant_planner_provider || "";
normalized.assistant_planner_provider =
llm?.assistant_planner_provider || "";
normalized.assistant_planner_model = llm?.assistant_planner_model || "";
return normalized;
}
@@ -116,7 +118,9 @@
function getProviderById(providerId) {
if (!providerId) return null;
return (settings?.llm_providers || []).find((p) => p.id === providerId) || null;
return (
(settings?.llm_providers || []).find((p) => p.id === providerId) || null
);
}
function isDashboardValidationBindingValid() {
@@ -129,6 +133,9 @@
// Handle tab change
function handleTabChange(tab) {
activeTab = tab;
if (tab === "migration") {
loadMigrationSettings();
}
}
// Get tab class
@@ -138,6 +145,44 @@
: "text-gray-600 hover:text-gray-800 border-transparent hover:border-gray-300";
}
// Migration Settings State
let migrationCron = "0 2 * * *";
let displayMappings = [];
let isSavingMigration = false;
let isLoadingMigration = false;
async function loadMigrationSettings() {
isLoadingMigration = true;
try {
const settingsRes = await api.requestApi("/migration/settings");
migrationCron = settingsRes.cron;
const mappingsRes = await api.requestApi("/migration/mappings-data");
displayMappings = mappingsRes;
} catch (err) {
console.error("[SettingsPage][Migration] Failed to load:", err);
} finally {
isLoadingMigration = false;
}
}
async function saveMigrationSettings() {
isSavingMigration = true;
try {
await api.putApi("/migration/settings", { cron: migrationCron });
addToast(
$t.settings?.save_success || "Migration settings saved",
"success",
);
} catch (err) {
addToast(
$t.settings?.save_failed || "Failed to save migration settings",
"error",
);
} finally {
isSavingMigration = false;
}
}
// Handle global settings save (Logging, Storage)
async function handleSave() {
console.log("[SettingsPage][Action] Saving settings");
@@ -327,6 +372,14 @@
>
{$t.settings?.llm || "LLM"}
</button>
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'migration',
)}"
on:click={() => handleTabChange("migration")}
>
Migration Sync
</button>
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'storage',
@@ -712,7 +765,8 @@
<div class="mt-6 rounded-lg border border-gray-200 bg-white p-4">
<h3 class="text-base font-semibold text-gray-900">
{$t.settings?.llm_chatbot_settings_title || "Chatbot Planner Settings"}
{$t.settings?.llm_chatbot_settings_title ||
"Chatbot Planner Settings"}
</h3>
<p class="mt-1 text-sm text-gray-600">
{$t.settings?.llm_chatbot_settings_description ||
@@ -721,7 +775,10 @@
<div class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label for="planner-provider" class="block text-sm font-medium text-gray-700">
<label
for="planner-provider"
class="block text-sm font-medium text-gray-700"
>
{$t.settings?.llm_chatbot_provider || "Chatbot Provider"}
</label>
<select
@@ -729,7 +786,9 @@
bind:value={settings.llm.assistant_planner_provider}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
<option value=""
>{$t.dashboard?.use_default || "Use Default"}</option
>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
@@ -739,14 +798,18 @@
</div>
<div>
<label for="planner-model" class="block text-sm font-medium text-gray-700">
<label
for="planner-model"
class="block text-sm font-medium text-gray-700"
>
{$t.settings?.llm_chatbot_model || "Chatbot Model Override"}
</label>
<input
id="planner-model"
type="text"
bind:value={settings.llm.assistant_planner_model}
placeholder={$t.settings?.llm_chatbot_model_placeholder || "Optional, e.g. gpt-4.1-mini"}
placeholder={$t.settings?.llm_chatbot_model_placeholder ||
"Optional, e.g. gpt-4.1-mini"}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
/>
</div>
@@ -755,7 +818,8 @@
<div class="mt-6 rounded-lg border border-gray-200 bg-white p-4">
<h3 class="text-base font-semibold text-gray-900">
{$t.settings?.llm_provider_bindings_title || "Provider Bindings by Task"}
{$t.settings?.llm_provider_bindings_title ||
"Provider Bindings by Task"}
</h3>
<p class="mt-1 text-sm text-gray-600">
{$t.settings?.llm_provider_bindings_description ||
@@ -764,15 +828,23 @@
<div class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label for="binding-dashboard-validation" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_binding_dashboard_validation || "Dashboard Validation Provider"}
<label
for="binding-dashboard-validation"
class="block text-sm font-medium text-gray-700"
>
{$t.settings?.llm_binding_dashboard_validation ||
"Dashboard Validation Provider"}
</label>
<select
id="binding-dashboard-validation"
bind:value={settings.llm.provider_bindings.dashboard_validation}
bind:value={
settings.llm.provider_bindings.dashboard_validation
}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
<option value=""
>{$t.dashboard?.use_default || "Use Default"}</option
>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
@@ -788,15 +860,21 @@
</div>
<div>
<label for="binding-documentation" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_binding_documentation || "Documentation Provider"}
<label
for="binding-documentation"
class="block text-sm font-medium text-gray-700"
>
{$t.settings?.llm_binding_documentation ||
"Documentation Provider"}
</label>
<select
id="binding-documentation"
bind:value={settings.llm.provider_bindings.documentation}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
<option value=""
>{$t.dashboard?.use_default || "Use Default"}</option
>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
@@ -806,7 +884,10 @@
</div>
<div class="md:col-span-2">
<label for="binding-git-commit" class="block text-sm font-medium text-gray-700">
<label
for="binding-git-commit"
class="block text-sm font-medium text-gray-700"
>
{$t.settings?.llm_binding_git_commit || "Git Commit Provider"}
</label>
<select
@@ -814,7 +895,9 @@
bind:value={settings.llm.provider_bindings.git_commit}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
<option value=""
>{$t.dashboard?.use_default || "Use Default"}</option
>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
@@ -840,7 +923,8 @@
for="documentation-prompt"
class="block text-sm font-medium text-gray-700"
>
{$t.settings?.llm_prompt_documentation || "Documentation Prompt"}
{$t.settings?.llm_prompt_documentation ||
"Documentation Prompt"}
</label>
<textarea
id="documentation-prompt"
@@ -892,6 +976,150 @@
</div>
</div>
</div>
{:else if activeTab === "migration"}
<!-- Migration Sync Tab -->
<div class="text-lg font-medium mb-4">
<h2 class="text-xl font-bold mb-4">
Cross-Environment ID Synchronization
</h2>
<p class="text-gray-600 mb-6">
Configure the background synchronization schedule and view the
currently mapped Dashboard, Chart, and Dataset IDs.
</p>
<!-- Cron Configuration -->
<div class="bg-gray-50 p-6 rounded-lg border border-gray-200 mb-6">
<h3 class="text-lg font-medium mb-4">Sync Schedule (Cron)</h3>
<div class="flex items-end gap-4">
<div class="flex-grow">
<label
for="migration_cron"
class="block text-sm font-medium text-gray-700"
>Cron Expression</label
>
<input
type="text"
id="migration_cron"
bind:value={migrationCron}
placeholder="0 2 * * *"
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2 font-mono text-sm"
/>
<p class="text-xs text-gray-500 mt-1">
Example: 0 2 * * * (daily at 2 AM UTC)
</p>
</div>
<button
on:click={saveMigrationSettings}
disabled={isSavingMigration}
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 h-[42px] min-w-[100px] flex items-center justify-center disabled:opacity-50"
>
{isSavingMigration ? "Saving..." : "Save"}
</button>
</div>
</div>
<!-- Mappings Table -->
<div class="bg-gray-50 p-6 rounded-lg border border-gray-200">
<h3
class="text-lg font-medium mb-4 flex items-center justify-between"
>
<span>Synchronized Resources</span>
<button
on:click={loadMigrationSettings}
class="text-sm text-indigo-600 hover:text-indigo-800 flex items-center gap-1"
disabled={isLoadingMigration}
>
<svg
class="w-4 h-4 {isLoadingMigration ? 'animate-spin' : ''}"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
></path></svg
>
Refresh
</button>
</h3>
<div class="overflow-x-auto border border-gray-200 rounded-lg">
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-100">
<tr>
<th
class="px-6 py-3 text-left font-medium text-gray-500 uppercase tracking-wider"
>Resource Name</th
>
<th
class="px-6 py-3 text-left font-medium text-gray-500 uppercase tracking-wider"
>Type</th
>
<th
class="px-6 py-3 text-left font-medium text-gray-500 uppercase tracking-wider"
>UUID</th
>
<th
class="px-6 py-3 text-left font-medium text-gray-500 uppercase tracking-wider"
>Target ID</th
>
<th
class="px-6 py-3 text-left font-medium text-gray-500 uppercase tracking-wider"
>Env</th
>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{#if isLoadingMigration && displayMappings.length === 0}
<tr
><td
colspan="5"
class="px-6 py-8 text-center text-gray-500"
>Loading mappings...</td
></tr
>
{:else if displayMappings.length === 0}
<tr
><td
colspan="5"
class="px-6 py-8 text-center text-gray-500"
>No synchronized resources found.</td
></tr
>
{:else}
{#each displayMappings as mapping}
<tr class="hover:bg-gray-50">
<td
class="px-6 py-4 whitespace-nowrap font-medium text-gray-900"
>{mapping.resource_name || "N/A"}</td
>
<td class="px-6 py-4 whitespace-nowrap"
><span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800"
>{mapping.resource_type}</span
></td
>
<td
class="px-6 py-4 whitespace-nowrap font-mono text-xs text-gray-500"
>{mapping.uuid}</td
>
<td
class="px-6 py-4 whitespace-nowrap font-mono text-xs font-bold text-gray-700"
>{mapping.remote_id}</td
>
<td class="px-6 py-4 whitespace-nowrap text-gray-500"
>{mapping.environment_id}</td
>
</tr>
{/each}
{/if}
</tbody>
</table>
</div>
</div>
</div>
{:else if activeTab === "storage"}
<!-- Storage Tab -->
<div class="text-lg font-medium mb-4">