refactor
This commit is contained in:
@@ -18,12 +18,29 @@
|
||||
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 settings = null;
|
||||
let isLoading = true;
|
||||
let error = null;
|
||||
|
||||
// Environment editing state
|
||||
let editingEnvId = null;
|
||||
let isAddingEnv = false;
|
||||
let newEnv = {
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: '',
|
||||
is_default: false,
|
||||
backup_schedule: {
|
||||
enabled: false,
|
||||
cron_expression: '0 0 * * *'
|
||||
}
|
||||
};
|
||||
|
||||
// Load settings on mount
|
||||
onMount(async () => {
|
||||
@@ -57,10 +74,13 @@
|
||||
: 'text-gray-600 hover:text-gray-800 border-transparent hover:border-gray-300';
|
||||
}
|
||||
|
||||
// Handle save
|
||||
// Handle global settings save (Logging, Storage)
|
||||
async function handleSave() {
|
||||
console.log('[SettingsPage][Action] Saving settings');
|
||||
try {
|
||||
// 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');
|
||||
} catch (err) {
|
||||
@@ -69,21 +89,89 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholder functions for environment actions
|
||||
function handleTestEnv(id) {
|
||||
// Handle environment actions
|
||||
async function handleTestEnv(id) {
|
||||
console.log(`[SettingsPage][Action] Test environment ${id}`);
|
||||
addToast('Environment test started', 'info');
|
||||
addToast('Testing connection...', 'info');
|
||||
try {
|
||||
const result = await api.testEnvironmentConnection(id);
|
||||
if (result.status === 'success') {
|
||||
addToast('Connection successful', 'success');
|
||||
} else {
|
||||
addToast(`Connection failed: ${result.message}`, 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[SettingsPage][Coherence:Failed] Error testing connection:', err);
|
||||
addToast('Failed to test connection', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function editEnv(env) {
|
||||
console.log(`[SettingsPage][Action] Edit environment ${env.id}`);
|
||||
// TODO: Open edit modal
|
||||
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 * * *' };
|
||||
}
|
||||
editingEnvId = env.id;
|
||||
isAddingEnv = false;
|
||||
}
|
||||
|
||||
function handleDeleteEnv(id) {
|
||||
function resetEnvForm() {
|
||||
newEnv = {
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: '',
|
||||
is_default: false,
|
||||
backup_schedule: {
|
||||
enabled: false,
|
||||
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;
|
||||
}
|
||||
|
||||
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?')) {
|
||||
console.log(`[SettingsPage][Action] Delete environment ${id}`);
|
||||
// TODO: Call API to delete
|
||||
try {
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -167,6 +255,12 @@
|
||||
>
|
||||
{$t.settings?.environments || 'Environments'}
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn {getTabClass('logging')}"
|
||||
on:click={() => handleTabChange('logging')}
|
||||
>
|
||||
{$t.settings?.logging || 'Logging'}
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn {getTabClass('connections')}"
|
||||
on:click={() => handleTabChange('connections')}
|
||||
@@ -179,12 +273,6 @@
|
||||
>
|
||||
{$t.settings?.llm || 'LLM'}
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn {getTabClass('logging')}"
|
||||
on:click={() => handleTabChange('logging')}
|
||||
>
|
||||
{$t.settings?.logging || 'Logging'}
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn {getTabClass('storage')}"
|
||||
on:click={() => handleTabChange('storage')}
|
||||
@@ -202,13 +290,87 @@
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$t.settings?.env_description || 'Configure Superset environments for dashboards and datasets.'}
|
||||
</p>
|
||||
<div class="flex justify-end mb-6">
|
||||
<button class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
|
||||
{$t.settings?.env_add || 'Add Environment'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if !editingEnvId && !isAddingEnv}
|
||||
<div class="flex justify-end mb-6">
|
||||
<button
|
||||
class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
|
||||
on:click={() => { isAddingEnv = true; resetEnvForm(); }}
|
||||
>
|
||||
{$t.settings?.env_add || 'Add Environment'}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#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>
|
||||
<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"
|
||||
/>
|
||||
</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" />
|
||||
</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" />
|
||||
</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" />
|
||||
</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" />
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex gap-2 justify-end">
|
||||
<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}
|
||||
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
|
||||
>
|
||||
{editingEnvId ? 'Update' : 'Add'} Environment
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if settings.environments && settings.environments.length > 0}
|
||||
<div class="mt-6">
|
||||
<div class="mt-6 overflow-x-auto border border-gray-200 rounded-lg">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
@@ -225,13 +387,21 @@
|
||||
<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.is_default ? 'Yes' : 'No'}</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">
|
||||
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)}>
|
||||
{$t.settings?.env_test || "Test"}
|
||||
</button>
|
||||
<button class="text-indigo-600 hover:text-indigo-900 mr-4" on:click={() => editEnv(env)}>
|
||||
{$t.common.edit}
|
||||
{$t.common.edit || "Edit"}
|
||||
</button>
|
||||
<button class="text-red-600 hover:text-red-900" on:click={() => handleDeleteEnv(env.id)}>
|
||||
{$t.settings?.env_delete || "Delete"}
|
||||
@@ -242,29 +412,13 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{:else if !isAddingEnv}
|
||||
<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>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{: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>
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$t.settings?.connections_description || 'Configure database connections for data mapping.'}
|
||||
</p>
|
||||
</div>
|
||||
{: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>
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$t.settings?.llm_description || 'Configure LLM providers for dataset documentation.'}
|
||||
</p>
|
||||
<div class="flex justify-end mb-6">
|
||||
<button class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
|
||||
{$t.llm?.add_provider || 'Add Provider'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else if activeTab === 'logging'}
|
||||
<!-- Logging Tab -->
|
||||
<div class="text-lg font-medium mb-4">
|
||||
@@ -272,6 +426,76 @@
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$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">
|
||||
<option value="DEBUG">DEBUG</option>
|
||||
<option value="INFO">INFO</option>
|
||||
<option value="WARNING">WARNING</option>
|
||||
<option value="ERROR">ERROR</option>
|
||||
<option value="CRITICAL">CRITICAL</option>
|
||||
</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">
|
||||
<option value="DEBUG">DEBUG</option>
|
||||
<option value="INFO">INFO</option>
|
||||
<option value="WARNING">WARNING</option>
|
||||
<option value="ERROR">ERROR</option>
|
||||
</select>
|
||||
</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>
|
||||
</label>
|
||||
<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}
|
||||
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
|
||||
>
|
||||
Save Logging Config
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{: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>
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$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>
|
||||
{: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>
|
||||
{/if}
|
||||
</div>
|
||||
{: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>
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$t.settings?.llm_description || 'Configure LLM providers for dataset documentation.'}
|
||||
</p>
|
||||
|
||||
<ProviderConfig providers={settings.llm_providers || []} onSave={loadSettings} />
|
||||
</div>
|
||||
{:else if activeTab === 'storage'}
|
||||
<!-- Storage Tab -->
|
||||
@@ -280,6 +504,32 @@
|
||||
<p class="text-gray-600 mb-6">
|
||||
{$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>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user