diff --git a/wwwroot/css/base.css b/wwwroot/css/base.css index 822f579..833b122 100644 --- a/wwwroot/css/base.css +++ b/wwwroot/css/base.css @@ -93,6 +93,19 @@ button.icon-btn:hover { border-color: transparent; } +button.icon-btn[title="Deaktivieren"], +button.icon-btn[data-tooltip="Deaktivieren"] { + border-color: var(--primary); + background: var(--primary); + color: var(--f1-bg); +} + +.admin-user-row:has(button.icon-btn[title="Deaktivieren"]), +.admin-user-row:has(button.icon-btn[data-tooltip="Deaktivieren"]) { + border-color: var(--primary); + filter: brightness(1.1); +} + textarea, code, pre, .tool-input, .tool-diff, .tool-result { font-family: var(--mono); font-size: var(--mono-size); diff --git a/wwwroot/css/form.css b/wwwroot/css/form.css index d5e3786..b2b7341 100644 --- a/wwwroot/css/form.css +++ b/wwwroot/css/form.css @@ -572,6 +572,7 @@ label.skill-item { .admin-user-list { display: flex; flex-direction: column; + gap: var(--badge-spacing); } .admin-user-row { @@ -579,6 +580,9 @@ label.skill-item { align-items: center; justify-content: space-between; padding: var(--box-padding); + border: 1px solid var(--f1-border); + border-radius: var(--border-radius); + background: color-mix(in srgb, var(--f1-bg) 25%, transparent); } .admin-user-info { diff --git a/wwwroot/css/placeholder.css b/wwwroot/css/placeholder.css index 7894262..1b66c91 100644 --- a/wwwroot/css/placeholder.css +++ b/wwwroot/css/placeholder.css @@ -25,9 +25,9 @@ justify-content: space-between; gap: var(--box-spacing); padding: var(--box-padding); - background: var(--f1-bg); - border: var(--border-width) solid var(--f1-border); + border: 1px solid var(--f1-border); border-radius: var(--border-radius); + background: color-mix(in srgb, var(--f1-bg) 25%, transparent); } .setting-info { diff --git a/wwwroot/js/pages/api-keys-page.js b/wwwroot/js/pages/api-keys-page.js index 93bb445..3e2812d 100644 --- a/wwwroot/js/pages/api-keys-page.js +++ b/wwwroot/js/pages/api-keys-page.js @@ -98,7 +98,6 @@ registerPage('api-keys', { var metaSpan = document.createElement('span'); metaSpan.className = 'admin-user-meta'; var parts = [key.provider]; - if (key.isActive) parts.push('✅ Aktiv'); parts.push(formatKeyStatus(key.status)); if (key.plan) parts.push(key.plan); if (key.checkedAt) parts.push(new Date(key.checkedAt).toLocaleString()); @@ -115,27 +114,50 @@ registerPage('api-keys', { info.appendChild(urlSpan); } info.appendChild(metaSpan); - var usageBadge = createUsageBadge(key.usage5h, key.usage7d); - if (usageBadge) info.appendChild(usageBadge); - var actions = document.createElement('div'); - actions.className = 'admin-user-actions'; + // Toggle + Usage-Badge nebeneinander + var badgeRow = document.createElement('div'); + badgeRow.style.cssText = 'display:flex;align-items:center;gap:8px;margin-top:2px'; + + if (key.isActive) { + var deactivateBtn = document.createElement('button'); + deactivateBtn.className = 'icon-btn'; + deactivateBtn.title = 'Deaktivieren'; + deactivateBtn.innerHTML = ''; + deactivateBtn.addEventListener('click', function() { deactivateKey(key); }); + badgeRow.appendChild(deactivateBtn); + } else { + var activateBtn = document.createElement('button'); + activateBtn.className = 'icon-btn'; + activateBtn.title = 'Aktivieren'; + activateBtn.innerHTML = ''; + activateBtn.addEventListener('click', function() { activateKey(key); }); + badgeRow.appendChild(activateBtn); + } + + var usageBadge = createUsageBadge(key.usage5h, key.usage7d); + if (usageBadge) badgeRow.appendChild(usageBadge); // Status-Zeile (für Check-Ergebnis) var statusLine = document.createElement('div'); statusLine.className = 'admin-user-meta'; statusLine.style.cssText = 'padding:0 var(--box-padding) .5rem;display:none;font-size:.85em'; - // Check (nur Anthropic) + // Check (nur Anthropic) – rechts neben Usage-Badge if (key.provider === 'anthropic') { var checkBtn = document.createElement('button'); checkBtn.className = 'icon-btn'; checkBtn.title = 'Key prüfen'; checkBtn.innerHTML = ''; checkBtn.addEventListener('click', function() { checkKey(key, checkBtn, statusLine); }); - actions.appendChild(checkBtn); + badgeRow.appendChild(checkBtn); } + info.appendChild(badgeRow); + + var actions = document.createElement('div'); + actions.className = 'admin-user-actions'; + // Bearbeiten var editBtn = document.createElement('button'); editBtn.className = 'icon-btn'; @@ -144,23 +166,6 @@ registerPage('api-keys', { editBtn.addEventListener('click', function() { startEdit(key); }); actions.appendChild(editBtn); - // Aktivieren/Deaktivieren - if (key.isActive) { - var deactivateBtn = document.createElement('button'); - deactivateBtn.className = 'icon-btn'; - deactivateBtn.title = 'Deaktivieren'; - deactivateBtn.innerHTML = ''; - deactivateBtn.addEventListener('click', function() { deactivateKey(key); }); - actions.appendChild(deactivateBtn); - } else { - var activateBtn = document.createElement('button'); - activateBtn.className = 'icon-btn'; - activateBtn.title = 'Aktivieren'; - activateBtn.innerHTML = ''; - activateBtn.addEventListener('click', function() { activateKey(key); }); - actions.appendChild(activateBtn); - } - // Löschen var deleteBtn = document.createElement('button'); deleteBtn.className = 'icon-btn'; @@ -190,9 +195,8 @@ registerPage('api-keys', { var origHtml = btn.innerHTML; btn.innerHTML = ''; btn.disabled = true; - statusLine.style.display = 'block'; - statusLine.textContent = 'Prüfe…'; - statusLine.style.opacity = '0.5'; + statusLine.style.display = 'none'; + statusLine.innerHTML = ''; try { var result = await apiCheckApiKey(key.keyId); statusLine.style.opacity = '1'; @@ -322,7 +326,8 @@ registerPage('api-keys', { function renderScannedKeys() { scannedList.innerHTML = ''; - if (scannedKeys.length === 0) { + var visibleKeys = scannedKeys.filter(function(sk) { return sk.adoptedApiKeyId == null; }); + if (visibleKeys.length === 0) { var empty = document.createElement('div'); empty.className = 'admin-user-meta'; empty.style.padding = '1rem 0'; @@ -331,12 +336,10 @@ registerPage('api-keys', { return; } - scannedKeys.forEach(function(sk) { - var isAdopted = sk.adoptedApiKeyId != null; + visibleKeys.forEach(function(sk) { var row = document.createElement('div'); row.className = 'admin-user-row'; - if (isAdopted) row.style.opacity = '0.5'; var info = document.createElement('div'); info.className = 'admin-user-info'; @@ -354,7 +357,7 @@ registerPage('api-keys', { var metaSpan = document.createElement('span'); metaSpan.className = 'admin-user-meta'; - var metaParts = isAdopted ? ['📥 Übernommen'] : []; + var metaParts = []; metaParts.push(formatKeyStatus(sk.status)); if (sk.plan && sk.plan !== 'Unknown') metaParts.push(sk.plan); if (sk.checkedAt) metaParts.push(new Date(sk.checkedAt).toLocaleString()); @@ -367,54 +370,52 @@ registerPage('api-keys', { var actions = document.createElement('div'); actions.className = 'admin-user-actions'; - if (!isAdopted) { - // Recheck - var recheckBtn = document.createElement('button'); - recheckBtn.className = 'icon-btn'; - recheckBtn.title = 'Erneut prüfen'; - recheckBtn.innerHTML = ''; - recheckBtn.addEventListener('click', async function() { - recheckBtn.innerHTML = ''; - recheckBtn.disabled = true; - try { - await apiRecheckScannedKey(sk.scannedKeyId); - await loadScannedKeys(); - } catch (err) { showToast(err.message, 'error'); } - finally { recheckBtn.innerHTML = ''; recheckBtn.disabled = false; } - }); - actions.appendChild(recheckBtn); + // Recheck + var recheckBtn = document.createElement('button'); + recheckBtn.className = 'icon-btn'; + recheckBtn.title = 'Erneut prüfen'; + recheckBtn.innerHTML = ''; + recheckBtn.addEventListener('click', async function() { + recheckBtn.innerHTML = ''; + recheckBtn.disabled = true; + try { + await apiRecheckScannedKey(sk.scannedKeyId); + await loadScannedKeys(); + } catch (err) { showToast(err.message, 'error'); } + finally { recheckBtn.innerHTML = ''; recheckBtn.disabled = false; } + }); + actions.appendChild(recheckBtn); - // Übernehmen (bei valid oder quota_exceeded) - if (sk.status === 'valid' || sk.status === 'quota_exceeded') { - var adoptBtn = document.createElement('button'); - adoptBtn.className = 'icon-btn'; - adoptBtn.title = 'Als API-Key übernehmen'; - adoptBtn.innerHTML = ''; - adoptBtn.addEventListener('click', async function() { - try { - await apiAdoptScannedKey(sk.scannedKeyId); - showToast('Key übernommen'); - await loadScannedKeys(); - await loadKeys(); - } catch (err) { showToast(err.message, 'error'); } - }); - actions.appendChild(adoptBtn); - } - - // Löschen - var delBtn = document.createElement('button'); - delBtn.className = 'icon-btn'; - delBtn.title = 'Ignorieren'; - delBtn.innerHTML = ''; - delBtn.addEventListener('click', async function() { + // Übernehmen (bei valid oder quota_exceeded) + if (sk.status === 'valid' || sk.status === 'quota_exceeded') { + var adoptBtn = document.createElement('button'); + adoptBtn.className = 'icon-btn'; + adoptBtn.title = 'Als API-Key übernehmen'; + adoptBtn.innerHTML = ''; + adoptBtn.addEventListener('click', async function() { try { - await apiDeleteScannedKey(sk.scannedKeyId); + await apiAdoptScannedKey(sk.scannedKeyId); + showToast('Key übernommen'); await loadScannedKeys(); + await loadKeys(); } catch (err) { showToast(err.message, 'error'); } }); - actions.appendChild(delBtn); + actions.appendChild(adoptBtn); } + // Löschen + var delBtn = document.createElement('button'); + delBtn.className = 'icon-btn'; + delBtn.title = 'Ignorieren'; + delBtn.innerHTML = ''; + delBtn.addEventListener('click', async function() { + try { + await apiDeleteScannedKey(sk.scannedKeyId); + await loadScannedKeys(); + } catch (err) { showToast(err.message, 'error'); } + }); + actions.appendChild(delBtn); + row.appendChild(info); row.appendChild(actions); scannedList.appendChild(row);