feat(admin): Provider & Sprache — Eigener-Wert-Eingabe + Tests (v14)

app.js: default_stt/llm/tts_provider und default_language von 'select'
auf 'combo' umgestellt, damit neben den vordefinierten Optionen jederzeit
ein beliebiger eigener Wert eingegeben werden kann (Zukunftssicherheit).
combo-Renderer unterstützt jetzt auch meta.labels (Sprachkürzel → Klarname).
tests/test_admin_settings.py: 28 Tests für GET/PUT/DELETE /api/admin/config —
Auth, bekannte Werte, Custom-Values, Persistenz, Runtime-Wirkung.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-19 12:30:52 +02:00
commit 4a4cbe643d
4 changed files with 199 additions and 9 deletions

View file

@ -976,10 +976,10 @@ $("#log-clear").addEventListener("click", () => { $("#log-output").innerHTML = "
// Metadaten für jedes Feld: UI-Typ, Optionen, Test-Typ
const FIELD_META = {
default_stt_provider: { ui: "select", opts: ["openrouter","faster-whisper"], test: "stt" },
default_llm_provider: { ui: "select", opts: ["openrouter","local-openai-compatible"], test: "llm" },
default_tts_provider: { ui: "select", opts: ["openrouter","piper","chatterbox"], test: "tts" },
default_language: { ui: "select", opts: ["de","en","fr","es","it","nl"],
default_stt_provider: { ui: "combo", opts: ["openrouter","faster-whisper"], test: "stt" },
default_llm_provider: { ui: "combo", opts: ["openrouter","local-openai-compatible"], test: "llm" },
default_tts_provider: { ui: "combo", opts: ["openrouter","piper","chatterbox"], test: "tts" },
default_language: { ui: "combo", opts: ["de","en","fr","es","it","nl"],
labels: { de:"Deutsch",en:"Englisch",fr:"Französisch",es:"Spanisch",it:"Italienisch",nl:"Niederländisch" } },
openrouter_llm_model: { ui: "combo", opts: ["google/gemini-3.1-flash-lite","openai/gpt-4.1-mini","google/gemini-2.5-flash","anthropic/claude-haiku-4-5-20251001","meta-llama/llama-3.3-70b-instruct"], test: "llm" },
openrouter_tts_model: { ui: "combo", opts: ["google/gemini-3.1-flash-tts-preview","openai/gpt-4o-mini-tts"], test: "tts" },
@ -1050,8 +1050,9 @@ function _buildControl(item, meta) {
if (meta.ui === "combo") {
const inList = meta.opts.includes(val);
const labels = meta.labels || {};
const options = meta.opts.map((o) =>
`<option value="${escHtml(o)}" ${o === val ? "selected" : ""}>${escHtml(o)}</option>`
`<option value="${escHtml(o)}" ${o === val ? "selected" : ""}>${escHtml(labels[o] || o)}</option>`
).join("");
const customSel = !inList ? 'selected' : '';
return `

View file

@ -218,6 +218,6 @@
<div id="status" class="w-full max-w-3xl mx-auto mt-1 min-h-[1rem] text-xs text-slate-500 dark:text-slate-400"></div>
</footer>
<script src="/app.js?v=13"></script>
<script src="/app.js?v=14"></script>
</body>
</html>