feat: Settings in Datenbank speichern statt localStorage

- Neue Spalte 'settings' in users-Tabelle (Migration via TryAddColumn)
- SettingsEndpoint: GET/PUT /api/settings
- DatabaseService: GetUserSettings() + UpdateUserSettings()
- Frontend: currentSettings als globaler State in app.js
- settings-page.js: localStorage komplett entfernt, nutzt API
- Settings werden beim App-Start aus DB geladen und angewendet
This commit is contained in:
Meleki committed 2026-03-03 16:47:56 +01:00
1 parent aac10901fa
commit a0752ea492
8 files changed
+102 -43

No files matched your search

+1 -1
View File
@@ -79,7 +79,6 @@ header {
display: flex;
flex-direction: column;
overflow: hidden;
transition: var(--transition-duration);
}
.page-content {
@@ -96,4 +95,5 @@ header,
width: var(--page-width);
max-width: 100%;
align-self: center;
transition: width var(--transition-duration);
}
+15
View File
@@ -306,6 +306,21 @@ async function apiTelegramDeleteWebhook() {
return resp.json();
}
async function apiGetSettings() {
const resp = await fetch('/api/settings');
if (!resp.ok) return {};
return resp.json();
}
async function apiSaveSettings(settings) {
const resp = await fetch('/api/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(settings)
});
return resp.json();
}
async function apiBackupDb() {
const resp = await fetch('/api/backup', { method: 'POST', credentials: 'include' });
if (!resp.ok) throw new Error('Backup fehlgeschlagen');
+26 -1
View File
@@ -1,5 +1,28 @@
// ── Global User State ──
// ── Global State ──
var currentUser = null;
var currentSettings = null;
const SETTINGS_DEFAULTS = {
pageWidth: 900,
toolCallDisplay: 'modifications',
chainMetaDisplay: 'sometimes',
showDeletedMessages: false
};
function loadSettings() {
return Object.assign({}, SETTINGS_DEFAULTS, currentSettings);
}
async function saveSettings(settings) {
currentSettings = settings;
applySettings();
try { await apiSaveSettings(settings); } catch (_) {}
}
function applySettings() {
var s = loadSettings();
document.documentElement.style.setProperty('--page-width', s.pageWidth + 'px');
}
// ── App Init ──
@@ -12,6 +35,8 @@ document.addEventListener('DOMContentLoaded', async () => {
}
currentUser = user;
currentSettings = await apiGetSettings();
applySettings();
loadClaudeStatus();
const { page, id } = parseHash();
+6 -41
View File
@@ -1,38 +1,5 @@
// ── Settings Page ──
const SETTINGS_KEY = 'settings';
const SETTINGS_DEFAULTS = {
pageWidth: 900,
toolCallDisplay: 'modifications', // 'all' | 'modifications' | 'hidden'
chainMetaDisplay: 'sometimes', // 'always' | 'sometimes' | 'never'
showDeletedMessages: false
};
function loadSettings() {
try {
const raw = localStorage.getItem(SETTINGS_KEY);
if (raw) return Object.assign({}, SETTINGS_DEFAULTS, JSON.parse(raw));
} catch (_) {}
return Object.assign({}, SETTINGS_DEFAULTS);
}
function saveSettings(settings) {
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
}
function resetSettings() {
localStorage.removeItem(SETTINGS_KEY);
}
function applySettings() {
const s = loadSettings();
document.documentElement.style.setProperty('--page-width', s.pageWidth + 'px');
}
// Apply on load
applySettings();
registerPage('settings', {
init() {
const slider = document.getElementById('settingPageWidth');
@@ -62,26 +29,25 @@ registerPage('settings', {
});
slider.addEventListener('change', () => {
const s = loadSettings();
var s = loadSettings();
s.pageWidth = parseInt(slider.value, 10);
saveSettings(s);
applySettings();
});
toolCallSelect.addEventListener('change', () => {
const s = loadSettings();
var s = loadSettings();
s.toolCallDisplay = toolCallSelect.value;
saveSettings(s);
});
chainMetaSelect.addEventListener('change', () => {
const s = loadSettings();
var s = loadSettings();
s.chainMetaDisplay = chainMetaSelect.value;
saveSettings(s);
});
showDeletedToggle.addEventListener('change', () => {
const s = loadSettings();
var s = loadSettings();
s.showDeletedMessages = showDeletedToggle.checked;
saveSettings(s);
});
@@ -100,10 +66,9 @@ registerPage('settings', {
}
});
resetBtn.addEventListener('click', () => {
resetBtn.addEventListener('click', async () => {
if (!confirm('Alle Einstellungen auf Standard zurücksetzen?')) return;
resetSettings();
applySettings();
await saveSettings(Object.assign({}, SETTINGS_DEFAULTS));
// Update UI
slider.value = SETTINGS_DEFAULTS.pageWidth;
display.textContent = SETTINGS_DEFAULTS.pageWidth + 'px';