css refactor

This commit is contained in:
2026-02-19 18:24:36 +03:00
parent 4de5b22d57
commit fdcbe32dfa
45 changed files with 1798 additions and 1857 deletions

View File

@@ -6,7 +6,7 @@
* @LAYER: UI
* @RELATION: BINDS_TO -> sidebarStore
* @INVARIANT: Always shows tabbed interface with all settings categories
*
*
* @UX_STATE: Loading -> Shows skeleton loader
* @UX_STATE: Loaded -> Shows tabbed settings interface
* @UX_STATE: Error -> Shows error banner with retry button
@@ -14,32 +14,32 @@
* @UX_RECOVERY: Refresh button reloads settings data
*/
import { onMount } from 'svelte';
import { t } from '$lib/i18n';
import { api } from '$lib/api.js';
import { addToast } from '$lib/toasts';
import ProviderConfig from '../../components/llm/ProviderConfig.svelte';
import { onMount } from "svelte";
import { t } from "$lib/i18n";
import { api } from "$lib/api.js";
import { addToast } from "$lib/toasts";
import ProviderConfig from "../../components/llm/ProviderConfig.svelte";
// State
let activeTab = 'environments';
let activeTab = "environments";
let settings = null;
let isLoading = true;
let error = null;
// Environment editing state
let editingEnvId = null;
let isAddingEnv = false;
let newEnv = {
id: '',
name: '',
url: '',
username: '',
password: '',
id: "",
name: "",
url: "",
username: "",
password: "",
is_default: false,
backup_schedule: {
enabled: false,
cron_expression: '0 0 * * *'
}
cron_expression: "0 0 * * *",
},
};
// Load settings on mount
@@ -55,8 +55,8 @@
const response = await api.getConsolidatedSettings();
settings = response;
} catch (err) {
error = err.message || 'Failed to load settings';
console.error('[SettingsPage][Coherence:Failed]', err);
error = err.message || "Failed to load settings";
console.error("[SettingsPage][Coherence:Failed]", err);
} finally {
isLoading = false;
}
@@ -70,39 +70,42 @@
// Get tab class
function getTabClass(tab) {
return activeTab === tab
? 'text-blue-600 border-b-2 border-blue-600'
: 'text-gray-600 hover:text-gray-800 border-transparent hover:border-gray-300';
? "text-blue-600 border-b-2 border-blue-600"
: "text-gray-600 hover:text-gray-800 border-transparent hover:border-gray-300";
}
// Handle global settings save (Logging, Storage)
async function handleSave() {
console.log('[SettingsPage][Action] Saving settings');
console.log("[SettingsPage][Action] Saving settings");
try {
// In a real app we might want to only send the changed section,
// In a real app we might want to only send the changed section,
// but updateConsolidatedSettings expects full object or we can use specific endpoints.
// For now we use the consolidated update.
await api.updateConsolidatedSettings(settings);
addToast($t.settings?.save_success || 'Settings saved', 'success');
addToast($t.settings?.save_success || "Settings saved", "success");
} catch (err) {
console.error('[SettingsPage][Coherence:Failed]', err);
addToast($t.settings?.save_failed || 'Failed to save settings', 'error');
console.error("[SettingsPage][Coherence:Failed]", err);
addToast($t.settings?.save_failed || "Failed to save settings", "error");
}
}
// Handle environment actions
async function handleTestEnv(id) {
console.log(`[SettingsPage][Action] Test environment ${id}`);
addToast('Testing connection...', 'info');
addToast("Testing connection...", "info");
try {
const result = await api.testEnvironmentConnection(id);
if (result.status === 'success') {
addToast('Connection successful', 'success');
if (result.status === "success") {
addToast("Connection successful", "success");
} else {
addToast(`Connection failed: ${result.message}`, 'error');
addToast(`Connection failed: ${result.message}`, "error");
}
} catch (err) {
console.error('[SettingsPage][Coherence:Failed] Error testing connection:', err);
addToast('Failed to test connection', 'error');
console.error(
"[SettingsPage][Coherence:Failed] Error testing connection:",
err,
);
addToast("Failed to test connection", "error");
}
}
@@ -111,7 +114,7 @@
newEnv = JSON.parse(JSON.stringify(env)); // Deep copy
// Ensure backup_schedule exists
if (!newEnv.backup_schedule) {
newEnv.backup_schedule = { enabled: false, cron_expression: '0 0 * * *' };
newEnv.backup_schedule = { enabled: false, cron_expression: "0 0 * * *" };
}
editingEnvId = env.id;
isAddingEnv = false;
@@ -119,185 +122,177 @@
function resetEnvForm() {
newEnv = {
id: '',
name: '',
url: '',
username: '',
password: '',
id: "",
name: "",
url: "",
username: "",
password: "",
is_default: false,
backup_schedule: {
enabled: false,
cron_expression: '0 0 * * *'
}
cron_expression: "0 0 * * *",
},
};
editingEnvId = null;
}
async function handleAddOrUpdateEnv() {
try {
console.log(`[SettingsPage][Action] ${editingEnvId ? 'Updating' : 'Adding'} environment.`);
// Basic validation
if (!newEnv.id || !newEnv.name || !newEnv.url) {
addToast('Please fill in all required fields (ID, Name, URL)', 'error');
return;
}
try {
console.log(
`[SettingsPage][Action] ${editingEnvId ? "Updating" : "Adding"} environment.`,
);
if (editingEnvId) {
await api.updateEnvironment(editingEnvId, newEnv);
addToast('Environment updated', 'success');
} else {
await api.addEnvironment(newEnv);
addToast('Environment added', 'success');
}
resetEnvForm();
editingEnvId = null;
isAddingEnv = false;
await loadSettings();
} catch (error) {
console.error("[SettingsPage][Coherence:Failed] Failed to save environment:", error);
addToast(error.message || 'Failed to save environment', 'error');
// Basic validation
if (!newEnv.id || !newEnv.name || !newEnv.url) {
addToast("Please fill in all required fields (ID, Name, URL)", "error");
return;
}
if (editingEnvId) {
await api.updateEnvironment(editingEnvId, newEnv);
addToast("Environment updated", "success");
} else {
await api.addEnvironment(newEnv);
addToast("Environment added", "success");
}
resetEnvForm();
editingEnvId = null;
isAddingEnv = false;
await loadSettings();
} catch (error) {
console.error(
"[SettingsPage][Coherence:Failed] Failed to save environment:",
error,
);
addToast(error.message || "Failed to save environment", "error");
}
}
async function handleDeleteEnv(id) {
if (confirm('Are you sure you want to delete this environment?')) {
if (confirm("Are you sure you want to delete this environment?")) {
console.log(`[SettingsPage][Action] Delete environment ${id}`);
try {
await api.deleteEnvironment(id);
addToast('Environment deleted', 'success');
await loadSettings();
await api.deleteEnvironment(id);
addToast("Environment deleted", "success");
await loadSettings();
} catch (error) {
console.error("[SettingsPage][Coherence:Failed] Failed to delete environment:", error);
addToast('Failed to delete environment', 'error');
console.error(
"[SettingsPage][Coherence:Failed] Failed to delete environment:",
error,
);
addToast("Failed to delete environment", "error");
}
}
}
</script>
<style>
.container {
@apply max-w-7xl mx-auto px-4 py-6;
}
.header {
@apply flex items-center justify-between mb-6;
}
.title {
@apply text-2xl font-bold text-gray-900;
}
.refresh-btn {
@apply px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors;
}
.error-banner {
@apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4 flex items-center justify-between;
}
.retry-btn {
@apply px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition-colors;
}
.tabs {
@apply border-b border-gray-200 mb-6;
}
.tab-btn {
@apply px-4 py-2 text-sm font-medium transition-colors focus:outline-none;
}
.tab-content {
@apply bg-white rounded-lg p-6 border border-gray-200;
}
.skeleton {
@apply animate-pulse bg-gray-200 rounded;
}
</style>
<div class="container">
<div class="max-w-7xl mx-auto px-4 py-6">
<!-- Header -->
<div class="header">
<h1 class="title">{$t.settings?.title || 'Settings'}</h1>
<button class="refresh-btn" on:click={loadSettings}>
{$t.common?.refresh || 'Refresh'}
<div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-bold text-gray-900">
{$t.settings?.title || "Settings"}
</h1>
<button
class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-hover transition-colors"
on:click={loadSettings}
>
{$t.common?.refresh || "Refresh"}
</button>
</div>
<!-- Error Banner -->
{#if error}
<div class="error-banner">
<div
class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4 flex items-center justify-between"
>
<span>{error}</span>
<button class="retry-btn" on:click={loadSettings}>
{$t.common?.retry || 'Retry'}
<button
class="px-4 py-2 bg-destructive text-white rounded hover:bg-destructive-hover transition-colors"
on:click={loadSettings}
>
{$t.common?.retry || "Retry"}
</button>
</div>
{/if}
<!-- Loading State -->
{#if isLoading}
<div class="tab-content">
<div class="skeleton h-8"></div>
<div class="skeleton h-8"></div>
<div class="skeleton h-8"></div>
<div class="skeleton h-8"></div>
<div class="skeleton h-8"></div>
<div class="bg-white rounded-lg p-6 border border-gray-200">
<div class="animate-pulse bg-gray-200 rounded h-8"></div>
<div class="animate-pulse bg-gray-200 rounded h-8"></div>
<div class="animate-pulse bg-gray-200 rounded h-8"></div>
<div class="animate-pulse bg-gray-200 rounded h-8"></div>
<div class="animate-pulse bg-gray-200 rounded h-8"></div>
</div>
{:else if settings}
<!-- Tabs -->
<div class="tabs">
<button
class="tab-btn {getTabClass('environments')}"
on:click={() => handleTabChange('environments')}
<div class="border-b border-gray-200 mb-6">
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'environments',
)}"
on:click={() => handleTabChange("environments")}
>
{$t.settings?.environments || 'Environments'}
{$t.settings?.environments || "Environments"}
</button>
<button
class="tab-btn {getTabClass('logging')}"
on:click={() => handleTabChange('logging')}
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'logging',
)}"
on:click={() => handleTabChange("logging")}
>
{$t.settings?.logging || 'Logging'}
{$t.settings?.logging || "Logging"}
</button>
<button
class="tab-btn {getTabClass('connections')}"
on:click={() => handleTabChange('connections')}
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'connections',
)}"
on:click={() => handleTabChange("connections")}
>
{$t.settings?.connections || 'Connections'}
{$t.settings?.connections || "Connections"}
</button>
<button
class="tab-btn {getTabClass('llm')}"
on:click={() => handleTabChange('llm')}
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'llm',
)}"
on:click={() => handleTabChange("llm")}
>
{$t.settings?.llm || 'LLM'}
{$t.settings?.llm || "LLM"}
</button>
<button
class="tab-btn {getTabClass('storage')}"
on:click={() => handleTabChange('storage')}
<button
class="px-4 py-2 text-sm font-medium transition-colors focus:outline-none {getTabClass(
'storage',
)}"
on:click={() => handleTabChange("storage")}
>
{$t.settings?.storage || 'Storage'}
{$t.settings?.storage || "Storage"}
</button>
</div>
<!-- Tab Content -->
<div class="tab-content">
{#if activeTab === 'environments'}
<div class="bg-white rounded-lg p-6 border border-gray-200">
{#if activeTab === "environments"}
<!-- Environments Tab -->
<div class="text-lg font-medium mb-4">
<h2 class="text-xl font-bold mb-4">{$t.settings?.environments || 'Superset Environments'}</h2>
<h2 class="text-xl font-bold mb-4">
{$t.settings?.environments || "Superset Environments"}
</h2>
<p class="text-gray-600 mb-6">
{$t.settings?.env_description || 'Configure Superset environments for dashboards and datasets.'}
{$t.settings?.env_description ||
"Configure Superset environments for dashboards and datasets."}
</p>
{#if !editingEnvId && !isAddingEnv}
<div class="flex justify-end mb-6">
<button
<button
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
on:click={() => { isAddingEnv = true; resetEnvForm(); }}
on:click={() => {
isAddingEnv = true;
resetEnvForm();
}}
>
{$t.settings?.env_add || 'Add Environment'}
{$t.settings?.env_add || "Add Environment"}
</button>
</div>
{/if}
@@ -305,65 +300,138 @@
{#if editingEnvId || isAddingEnv}
<!-- Add/Edit Environment Form -->
<div class="bg-gray-50 p-6 rounded-lg mb-6 border border-gray-200">
<h3 class="text-lg font-medium mb-4">{editingEnvId ? 'Edit' : 'Add'} Environment</h3>
<h3 class="text-lg font-medium mb-4">
{editingEnvId ? "Edit" : "Add"} Environment
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="env_id" class="block text-sm font-medium text-gray-700">ID</label>
<input
type="text"
id="env_id"
bind:value={newEnv.id}
disabled={!!editingEnvId}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2 disabled:bg-gray-100 disabled:text-gray-500"
<label
for="env_id"
class="block text-sm font-medium text-gray-700">ID</label
>
<input
type="text"
id="env_id"
bind:value={newEnv.id}
disabled={!!editingEnvId}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2 disabled:bg-gray-100 disabled:text-gray-500"
/>
</div>
<div>
<label for="env_name" class="block text-sm font-medium text-gray-700">Name</label>
<input type="text" id="env_name" bind:value={newEnv.name} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
<label
for="env_name"
class="block text-sm font-medium text-gray-700">Name</label
>
<input
type="text"
id="env_name"
bind:value={newEnv.name}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
<div>
<label for="env_url" class="block text-sm font-medium text-gray-700">URL</label>
<input type="text" id="env_url" bind:value={newEnv.url} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
<label
for="env_url"
class="block text-sm font-medium text-gray-700">URL</label
>
<input
type="text"
id="env_url"
bind:value={newEnv.url}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
<div>
<label for="env_user" class="block text-sm font-medium text-gray-700">Username</label>
<input type="text" id="env_user" bind:value={newEnv.username} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
<label
for="env_user"
class="block text-sm font-medium text-gray-700"
>Username</label
>
<input
type="text"
id="env_user"
bind:value={newEnv.username}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
<div>
<label for="env_pass" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="env_pass" bind:value={newEnv.password} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
<label
for="env_pass"
class="block text-sm font-medium text-gray-700"
>Password</label
>
<input
type="password"
id="env_pass"
bind:value={newEnv.password}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
<div class="flex items-center mt-6">
<input type="checkbox" id="env_default" bind:checked={newEnv.is_default} class="h-4 w-4 text-blue-600 border-gray-300 rounded" />
<label for="env_default" class="ml-2 block text-sm text-gray-900">Default Environment</label>
<input
type="checkbox"
id="env_default"
bind:checked={newEnv.is_default}
class="h-4 w-4 text-blue-600 border-gray-300 rounded"
/>
<label
for="env_default"
class="ml-2 block text-sm text-gray-900"
>Default Environment</label
>
</div>
</div>
<h3 class="text-lg font-medium mb-4 mt-6">Backup Schedule</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<input type="checkbox" id="backup_enabled" bind:checked={newEnv.backup_schedule.enabled} class="h-4 w-4 text-blue-600 border-gray-300 rounded" />
<label for="backup_enabled" class="ml-2 block text-sm text-gray-900">Enable Automatic Backups</label>
<input
type="checkbox"
id="backup_enabled"
bind:checked={newEnv.backup_schedule.enabled}
class="h-4 w-4 text-blue-600 border-gray-300 rounded"
/>
<label
for="backup_enabled"
class="ml-2 block text-sm text-gray-900"
>Enable Automatic Backups</label
>
</div>
<div>
<label for="cron_expression" class="block text-sm font-medium text-gray-700">Cron Expression</label>
<input type="text" id="cron_expression" bind:value={newEnv.backup_schedule.cron_expression} placeholder="0 0 * * *" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
<p class="text-xs text-gray-500 mt-1">Example: 0 0 * * * (daily at midnight)</p>
<label
for="cron_expression"
class="block text-sm font-medium text-gray-700"
>Cron Expression</label
>
<input
type="text"
id="cron_expression"
bind:value={newEnv.backup_schedule.cron_expression}
placeholder="0 0 * * *"
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
<p class="text-xs text-gray-500 mt-1">
Example: 0 0 * * * (daily at midnight)
</p>
</div>
</div>
<div class="mt-6 flex gap-2 justify-end">
<button
on:click={() => { isAddingEnv = false; editingEnvId = null; resetEnvForm(); }}
<button
on:click={() => {
isAddingEnv = false;
editingEnvId = null;
resetEnvForm();
}}
class="bg-gray-200 text-gray-700 px-4 py-2 rounded hover:bg-gray-300"
>
Cancel
</button>
<button
on:click={handleAddOrUpdateEnv}
<button
on:click={handleAddOrUpdateEnv}
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
>
{editingEnvId ? 'Update' : 'Add'} Environment
{editingEnvId ? "Update" : "Add"} Environment
</button>
</div>
</div>
@@ -374,11 +442,26 @@
<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">{$t.connections?.name || "Name"}</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">URL</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.connections?.user || "Username"}</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Default</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.settings?.env_actions || "Actions"}</th>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>{$t.connections?.name || "Name"}</th
>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>URL</th
>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>{$t.connections?.user || "Username"}</th
>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>Default</th
>
<th
class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"
>{$t.settings?.env_actions || "Actions"}</th
>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@@ -386,24 +469,38 @@
<tr>
<td class="px-6 py-4 whitespace-nowrap">{env.name}</td>
<td class="px-6 py-4 whitespace-nowrap">{env.url}</td>
<td class="px-6 py-4 whitespace-nowrap">{env.username}</td>
<td class="px-6 py-4 whitespace-nowrap">{env.username}</td
>
<td class="px-6 py-4 whitespace-nowrap">
{#if env.is_default}
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
>
Yes
</span>
{:else}
<span class="text-gray-500">No</span>
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button class="text-green-600 hover:text-green-900 mr-4" on:click={() => handleTestEnv(env.id)}>
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
>
<button
class="text-green-600 hover:text-green-900 mr-4"
on:click={() => handleTestEnv(env.id)}
>
{$t.settings?.env_test || "Test"}
</button>
<button class="text-indigo-600 hover:text-indigo-900 mr-4" on:click={() => editEnv(env)}>
<button
class="text-indigo-600 hover:text-indigo-900 mr-4"
on:click={() => editEnv(env)}
>
{$t.common.edit || "Edit"}
</button>
<button class="text-red-600 hover:text-red-900" on:click={() => handleDeleteEnv(env.id)}>
<button
class="text-red-600 hover:text-red-900"
on:click={() => handleDeleteEnv(env.id)}
>
{$t.settings?.env_delete || "Delete"}
</button>
</td>
@@ -413,25 +510,41 @@
</table>
</div>
{:else if !isAddingEnv}
<div class="mb-4 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700">
<div
class="mb-4 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700"
>
<p class="font-bold">Warning</p>
<p>No Superset environments configured. You must add at least one environment to perform backups or migrations.</p>
<p>
No Superset environments configured. You must add at least one
environment to perform backups or migrations.
</p>
</div>
{/if}
</div>
{:else if activeTab === 'logging'}
{:else if activeTab === "logging"}
<!-- Logging Tab -->
<div class="text-lg font-medium mb-4">
<h2 class="text-xl font-bold mb-4">{$t.settings?.logging || 'Logging Configuration'}</h2>
<h2 class="text-xl font-bold mb-4">
{$t.settings?.logging || "Logging Configuration"}
</h2>
<p class="text-gray-600 mb-6">
{$t.settings?.logging_description || 'Configure logging and task log levels.'}
{$t.settings?.logging_description ||
"Configure logging and task log levels."}
</p>
<div class="bg-gray-50 p-6 rounded-lg border border-gray-200">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="log_level" class="block text-sm font-medium text-gray-700">Log Level</label>
<select id="log_level" bind:value={settings.logging.level} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2">
<label
for="log_level"
class="block text-sm font-medium text-gray-700"
>Log Level</label
>
<select
id="log_level"
bind:value={settings.logging.level}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
>
<option value="DEBUG">DEBUG</option>
<option value="INFO">INFO</option>
<option value="WARNING">WARNING</option>
@@ -440,8 +553,16 @@
</select>
</div>
<div>
<label for="task_log_level" class="block text-sm font-medium text-gray-700">Task Log Level</label>
<select id="task_log_level" bind:value={settings.logging.task_log_level} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2">
<label
for="task_log_level"
class="block text-sm font-medium text-gray-700"
>Task Log Level</label
>
<select
id="task_log_level"
bind:value={settings.logging.task_log_level}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
>
<option value="DEBUG">DEBUG</option>
<option value="INFO">INFO</option>
<option value="WARNING">WARNING</option>
@@ -450,16 +571,25 @@
</div>
<div class="md:col-span-2">
<label class="flex items-center">
<input type="checkbox" id="enable_belief_state" bind:checked={settings.logging.enable_belief_state} class="h-4 w-4 text-blue-600 border-gray-300 rounded" />
<span class="ml-2 block text-sm text-gray-900">Enable Belief State Logging (Beta)</span>
<input
type="checkbox"
id="enable_belief_state"
bind:checked={settings.logging.enable_belief_state}
class="h-4 w-4 text-blue-600 border-gray-300 rounded"
/>
<span class="ml-2 block text-sm text-gray-900"
>Enable Belief State Logging (Beta)</span
>
</label>
<p class="text-xs text-gray-500 mt-1 ml-6">Logs agent reasoning and internal state changes for debugging.</p>
<p class="text-xs text-gray-500 mt-1 ml-6">
Logs agent reasoning and internal state changes for debugging.
</p>
</div>
</div>
<div class="mt-6 flex justify-end">
<button
on:click={handleSave}
<button
on:click={handleSave}
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
>
Save Logging Config
@@ -467,68 +597,114 @@
</div>
</div>
</div>
{:else if activeTab === 'connections'}
{:else if activeTab === "connections"}
<!-- Connections Tab -->
<div class="text-lg font-medium mb-4">
<h2 class="text-xl font-bold mb-4">{$t.settings?.connections || 'Database Connections'}</h2>
<h2 class="text-xl font-bold mb-4">
{$t.settings?.connections || "Database Connections"}
</h2>
<p class="text-gray-600 mb-6">
{$t.settings?.connections_description || 'Configure database connections for data mapping.'}
{$t.settings?.connections_description ||
"Configure database connections for data mapping."}
</p>
{#if settings.connections && settings.connections.length > 0}
<!-- Connections list would go here -->
<p class="text-gray-500 italic">No additional connections configured. Superset database connections are used by default.</p>
<!-- Connections list would go here -->
<p class="text-gray-500 italic">
No additional connections configured. Superset database
connections are used by default.
</p>
{:else}
<div class="text-center py-8 bg-gray-50 rounded-lg border border-dashed border-gray-300">
<p class="text-gray-500">No external connections configured.</p>
<button class="mt-4 px-4 py-2 border border-blue-600 text-blue-600 rounded hover:bg-blue-50">
Add Connection
</button>
</div>
<div
class="text-center py-8 bg-gray-50 rounded-lg border border-dashed border-gray-300"
>
<p class="text-gray-500">No external connections configured.</p>
<button
class="mt-4 px-4 py-2 border border-blue-600 text-blue-600 rounded hover:bg-blue-50"
>
Add Connection
</button>
</div>
{/if}
</div>
{:else if activeTab === 'llm'}
{:else if activeTab === "llm"}
<!-- LLM Tab -->
<div class="text-lg font-medium mb-4">
<h2 class="text-xl font-bold mb-4">{$t.settings?.llm || 'LLM Providers'}</h2>
<h2 class="text-xl font-bold mb-4">
{$t.settings?.llm || "LLM Providers"}
</h2>
<p class="text-gray-600 mb-6">
{$t.settings?.llm_description || 'Configure LLM providers for dataset documentation.'}
{$t.settings?.llm_description ||
"Configure LLM providers for dataset documentation."}
</p>
<ProviderConfig providers={settings.llm_providers || []} onSave={loadSettings} />
<ProviderConfig
providers={settings.llm_providers || []}
onSave={loadSettings}
/>
</div>
{:else if activeTab === 'storage'}
{:else if activeTab === "storage"}
<!-- Storage Tab -->
<div class="text-lg font-medium mb-4">
<h2 class="text-xl font-bold mb-4">{$t.settings?.storage || 'File Storage Configuration'}</h2>
<h2 class="text-xl font-bold mb-4">
{$t.settings?.storage || "File Storage Configuration"}
</h2>
<p class="text-gray-600 mb-6">
{$t.settings?.storage_description || 'Configure file storage paths and patterns.'}
{$t.settings?.storage_description ||
"Configure file storage paths and patterns."}
</p>
<div class="bg-gray-50 p-6 rounded-lg border border-gray-200">
<div class="grid grid-cols-1 gap-4">
<div>
<label for="storage_path" class="block text-sm font-medium text-gray-700">Root Path</label>
<input type="text" id="storage_path" bind:value={settings.storage.root_path} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
</div>
<div>
<label for="backup_path" class="block text-sm font-medium text-gray-700">Backup Path</label>
<input type="text" id="backup_path" bind:value={settings.storage.backup_path} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
</div>
<div>
<label for="repo_path" class="block text-sm font-medium text-gray-700">Repository Path</label>
<input type="text" id="repo_path" bind:value={settings.storage.repo_path} class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2" />
</div>
</div>
<div class="mt-6 flex justify-end">
<button
on:click={() => handleSave()}
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
>
Save Storage Config
</button>
</div>
<div class="grid grid-cols-1 gap-4">
<div>
<label
for="storage_path"
class="block text-sm font-medium text-gray-700"
>Root Path</label
>
<input
type="text"
id="storage_path"
bind:value={settings.storage.root_path}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
<div>
<label
for="backup_path"
class="block text-sm font-medium text-gray-700"
>Backup Path</label
>
<input
type="text"
id="backup_path"
bind:value={settings.storage.backup_path}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
<div>
<label
for="repo_path"
class="block text-sm font-medium text-gray-700"
>Repository Path</label
>
<input
type="text"
id="repo_path"
bind:value={settings.storage.repo_path}
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
/>
</div>
</div>
<div class="mt-6 flex justify-end">
<button
on:click={() => handleSave()}
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
>
Save Storage Config
</button>
</div>
</div>
</div>
{/if}

View File

@@ -175,8 +175,5 @@
</div>
<!-- [/SECTION: TEMPLATE] -->
<style>
/* Styles are handled by Tailwind */
</style>
<!-- [/DEF:GitSettingsPage:Component] -->