feat(settings): add Bild-Import (KI) section with key management and model picker

This commit is contained in:
Kenearos 2026-05-12 18:24:21 +02:00
parent 3b6283ced1
commit e3a8ae2d7b
2 changed files with 70 additions and 0 deletions

49
app.js
View file

@ -74,6 +74,21 @@ class DienstplanApp {
document.getElementById('export-btn').addEventListener('click', () => this.exportData());
document.getElementById('import-btn').addEventListener('click', () => this.importData());
document.getElementById('clear-all-btn').addEventListener('click', () => this.clearAllData());
// Bild-Import (KI) settings
const setKeyBtn = document.getElementById('set-api-key-btn');
if (setKeyBtn) setKeyBtn.addEventListener('click', () => this.setApiKeyFromPrompt());
const clearKeyBtn = document.getElementById('clear-api-key-btn');
if (clearKeyBtn) clearKeyBtn.addEventListener('click', () => this.clearApiKey());
const modelSelect = document.getElementById('api-model-select');
if (modelSelect) {
modelSelect.value = this.storage.getApiModel();
modelSelect.addEventListener('change', () => {
this.storage.setApiModel(modelSelect.value);
this.showToast(`Modell geaendert: ${modelSelect.options[modelSelect.selectedIndex].text}`, 'success');
});
}
this.refreshApiKeyStatus();
}
/**
@ -141,6 +156,8 @@ class DienstplanApp {
this.loadEmployeeList();
} else if (tabName === 'duties') {
this.loadDutiesForSelectedEmployee();
} else if (tabName === 'settings') {
this.refreshApiKeyStatus();
}
}
@ -1036,6 +1053,38 @@ class DienstplanApp {
this.loadDutiesForSelectedEmployee();
}
/**
* Update the API-key status line in Settings.
*/
refreshApiKeyStatus() {
const el = document.getElementById('api-key-status');
if (!el) return;
if (this.storage.getApiKey()) {
el.textContent = 'API-Key gespeichert';
el.className = 'api-key-status-ok';
} else {
el.textContent = 'Kein Key hinterlegt';
el.className = 'api-key-status-none';
}
}
setApiKeyFromPrompt() {
const input = window.prompt('OpenRouter API-Key eingeben:', '');
if (input === null) return;
const trimmed = input.trim();
if (!trimmed) return;
this.storage.setApiKey(trimmed);
this.refreshApiKeyStatus();
this.showToast('API-Key gespeichert.', 'success');
}
clearApiKey() {
if (!window.confirm('API-Key wirklich loeschen?')) return;
this.storage.clearApiKey();
this.refreshApiKeyStatus();
this.showToast('API-Key geloescht.', 'info');
}
/**
* Show toast notification
*/

View file

@ -200,6 +200,27 @@
</div>
</div>
<div class="settings-section">
<h3>Bild-Import (KI)</h3>
<p id="api-key-status" class="api-key-status-none">Kein Key hinterlegt</p>
<button id="set-api-key-btn" class="btn btn-secondary">Key ändern</button>
<button id="clear-api-key-btn" class="btn btn-danger">Key löschen</button>
<div class="form-group" style="margin-top: 12px;">
<label for="api-model-select">Modell:</label>
<select id="api-model-select">
<option value="anthropic/claude-sonnet-4.6">Claude Sonnet 4.6</option>
<option value="google/gemini-2.5-pro">Gemini 2.5 Pro</option>
<option value="openai/gpt-4.1">GPT-4.1</option>
</select>
</div>
<p class="text-muted" style="margin-top: 10px;">
Hinweis: Der API-Key wird ausschließlich lokal in Ihrem Browser gespeichert
und nur an OpenRouter (openrouter.ai) gesendet.
</p>
</div>
<div class="settings-section">
<h3>Alle Daten löschen</h3>
<p class="text-warning">Achtung: Diese Aktion kann nicht rückgängig gemacht werden!</p>