API-Keys UI: Toggle+Check neben Badge, übernommene Keys ausblenden, Layout-Polish
- Toggle-Button (Aktivieren/Deaktivieren) links neben Usage-Badge
- Check-Button rechts neben Usage-Badge statt bei Actions
- '✅ Aktiv' aus Meta-Zeile entfernt (Toggle zeigt Status)
- 'Prüfe...' Text beim Check entfernt (Spinner im Button reicht)
- Übernommene Scanned-Keys komplett ausgeblendet statt halbtransparent
- isAdopted-Logik und Wrapper entfernt, Code entschachtelt
- admin-user-row: Border, Radius, Background hinzugefügt
- Aktive Keys visuell hervorgehoben (Primary-Border + Brightness)
- placeholder.css an gleichen Row-Style angeglichen
This commit is contained in:
1 parent
de388806cb
commit
bdcfd1f8b3
4 files changed
+93
-75
No files matched your search
@@ -93,6 +93,19 @@ button.icon-btn:hover {
|
|||||||
border-color: transparent;
|
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 {
|
textarea, code, pre, .tool-input, .tool-diff, .tool-result {
|
||||||
font-family: var(--mono);
|
font-family: var(--mono);
|
||||||
font-size: var(--mono-size);
|
font-size: var(--mono-size);
|
||||||
|
|||||||
@@ -572,6 +572,7 @@ label.skill-item {
|
|||||||
.admin-user-list {
|
.admin-user-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: var(--badge-spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-user-row {
|
.admin-user-row {
|
||||||
@@ -579,6 +580,9 @@ label.skill-item {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: var(--box-padding);
|
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 {
|
.admin-user-info {
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: var(--box-spacing);
|
gap: var(--box-spacing);
|
||||||
padding: var(--box-padding);
|
padding: var(--box-padding);
|
||||||
background: var(--f1-bg);
|
border: 1px solid var(--f1-border);
|
||||||
border: var(--border-width) solid var(--f1-border);
|
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
|
background: color-mix(in srgb, var(--f1-bg) 25%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-info {
|
.setting-info {
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ registerPage('api-keys', {
|
|||||||
var metaSpan = document.createElement('span');
|
var metaSpan = document.createElement('span');
|
||||||
metaSpan.className = 'admin-user-meta';
|
metaSpan.className = 'admin-user-meta';
|
||||||
var parts = [key.provider];
|
var parts = [key.provider];
|
||||||
if (key.isActive) parts.push('✅ Aktiv');
|
|
||||||
parts.push(formatKeyStatus(key.status));
|
parts.push(formatKeyStatus(key.status));
|
||||||
if (key.plan) parts.push(key.plan);
|
if (key.plan) parts.push(key.plan);
|
||||||
if (key.checkedAt) parts.push(new Date(key.checkedAt).toLocaleString());
|
if (key.checkedAt) parts.push(new Date(key.checkedAt).toLocaleString());
|
||||||
@@ -115,27 +114,50 @@ registerPage('api-keys', {
|
|||||||
info.appendChild(urlSpan);
|
info.appendChild(urlSpan);
|
||||||
}
|
}
|
||||||
info.appendChild(metaSpan);
|
info.appendChild(metaSpan);
|
||||||
var usageBadge = createUsageBadge(key.usage5h, key.usage7d);
|
|
||||||
if (usageBadge) info.appendChild(usageBadge);
|
|
||||||
|
|
||||||
var actions = document.createElement('div');
|
// Toggle + Usage-Badge nebeneinander
|
||||||
actions.className = 'admin-user-actions';
|
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 = '<i class="fa fa-toggle-on" style="color:var(--accent)"></i>';
|
||||||
|
deactivateBtn.addEventListener('click', function() { deactivateKey(key); });
|
||||||
|
badgeRow.appendChild(deactivateBtn);
|
||||||
|
} else {
|
||||||
|
var activateBtn = document.createElement('button');
|
||||||
|
activateBtn.className = 'icon-btn';
|
||||||
|
activateBtn.title = 'Aktivieren';
|
||||||
|
activateBtn.innerHTML = '<i class="fa fa-toggle-off"></i>';
|
||||||
|
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)
|
// Status-Zeile (für Check-Ergebnis)
|
||||||
var statusLine = document.createElement('div');
|
var statusLine = document.createElement('div');
|
||||||
statusLine.className = 'admin-user-meta';
|
statusLine.className = 'admin-user-meta';
|
||||||
statusLine.style.cssText = 'padding:0 var(--box-padding) .5rem;display:none;font-size:.85em';
|
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') {
|
if (key.provider === 'anthropic') {
|
||||||
var checkBtn = document.createElement('button');
|
var checkBtn = document.createElement('button');
|
||||||
checkBtn.className = 'icon-btn';
|
checkBtn.className = 'icon-btn';
|
||||||
checkBtn.title = 'Key prüfen';
|
checkBtn.title = 'Key prüfen';
|
||||||
checkBtn.innerHTML = '<i class="fa fa-refresh"></i>';
|
checkBtn.innerHTML = '<i class="fa fa-refresh"></i>';
|
||||||
checkBtn.addEventListener('click', function() { checkKey(key, checkBtn, statusLine); });
|
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
|
// Bearbeiten
|
||||||
var editBtn = document.createElement('button');
|
var editBtn = document.createElement('button');
|
||||||
editBtn.className = 'icon-btn';
|
editBtn.className = 'icon-btn';
|
||||||
@@ -144,23 +166,6 @@ registerPage('api-keys', {
|
|||||||
editBtn.addEventListener('click', function() { startEdit(key); });
|
editBtn.addEventListener('click', function() { startEdit(key); });
|
||||||
actions.appendChild(editBtn);
|
actions.appendChild(editBtn);
|
||||||
|
|
||||||
// Aktivieren/Deaktivieren
|
|
||||||
if (key.isActive) {
|
|
||||||
var deactivateBtn = document.createElement('button');
|
|
||||||
deactivateBtn.className = 'icon-btn';
|
|
||||||
deactivateBtn.title = 'Deaktivieren';
|
|
||||||
deactivateBtn.innerHTML = '<i class="fa fa-toggle-on" style="color:var(--accent)"></i>';
|
|
||||||
deactivateBtn.addEventListener('click', function() { deactivateKey(key); });
|
|
||||||
actions.appendChild(deactivateBtn);
|
|
||||||
} else {
|
|
||||||
var activateBtn = document.createElement('button');
|
|
||||||
activateBtn.className = 'icon-btn';
|
|
||||||
activateBtn.title = 'Aktivieren';
|
|
||||||
activateBtn.innerHTML = '<i class="fa fa-toggle-off"></i>';
|
|
||||||
activateBtn.addEventListener('click', function() { activateKey(key); });
|
|
||||||
actions.appendChild(activateBtn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Löschen
|
// Löschen
|
||||||
var deleteBtn = document.createElement('button');
|
var deleteBtn = document.createElement('button');
|
||||||
deleteBtn.className = 'icon-btn';
|
deleteBtn.className = 'icon-btn';
|
||||||
@@ -190,9 +195,8 @@ registerPage('api-keys', {
|
|||||||
var origHtml = btn.innerHTML;
|
var origHtml = btn.innerHTML;
|
||||||
btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
statusLine.style.display = 'block';
|
statusLine.style.display = 'none';
|
||||||
statusLine.textContent = 'Prüfe…';
|
statusLine.innerHTML = '';
|
||||||
statusLine.style.opacity = '0.5';
|
|
||||||
try {
|
try {
|
||||||
var result = await apiCheckApiKey(key.keyId);
|
var result = await apiCheckApiKey(key.keyId);
|
||||||
statusLine.style.opacity = '1';
|
statusLine.style.opacity = '1';
|
||||||
@@ -322,7 +326,8 @@ registerPage('api-keys', {
|
|||||||
|
|
||||||
function renderScannedKeys() {
|
function renderScannedKeys() {
|
||||||
scannedList.innerHTML = '';
|
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');
|
var empty = document.createElement('div');
|
||||||
empty.className = 'admin-user-meta';
|
empty.className = 'admin-user-meta';
|
||||||
empty.style.padding = '1rem 0';
|
empty.style.padding = '1rem 0';
|
||||||
@@ -331,12 +336,10 @@ registerPage('api-keys', {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scannedKeys.forEach(function(sk) {
|
visibleKeys.forEach(function(sk) {
|
||||||
var isAdopted = sk.adoptedApiKeyId != null;
|
|
||||||
|
|
||||||
var row = document.createElement('div');
|
var row = document.createElement('div');
|
||||||
row.className = 'admin-user-row';
|
row.className = 'admin-user-row';
|
||||||
if (isAdopted) row.style.opacity = '0.5';
|
|
||||||
|
|
||||||
var info = document.createElement('div');
|
var info = document.createElement('div');
|
||||||
info.className = 'admin-user-info';
|
info.className = 'admin-user-info';
|
||||||
@@ -354,7 +357,7 @@ registerPage('api-keys', {
|
|||||||
|
|
||||||
var metaSpan = document.createElement('span');
|
var metaSpan = document.createElement('span');
|
||||||
metaSpan.className = 'admin-user-meta';
|
metaSpan.className = 'admin-user-meta';
|
||||||
var metaParts = isAdopted ? ['📥 Übernommen'] : [];
|
var metaParts = [];
|
||||||
metaParts.push(formatKeyStatus(sk.status));
|
metaParts.push(formatKeyStatus(sk.status));
|
||||||
if (sk.plan && sk.plan !== 'Unknown') metaParts.push(sk.plan);
|
if (sk.plan && sk.plan !== 'Unknown') metaParts.push(sk.plan);
|
||||||
if (sk.checkedAt) metaParts.push(new Date(sk.checkedAt).toLocaleString());
|
if (sk.checkedAt) metaParts.push(new Date(sk.checkedAt).toLocaleString());
|
||||||
@@ -367,54 +370,52 @@ registerPage('api-keys', {
|
|||||||
var actions = document.createElement('div');
|
var actions = document.createElement('div');
|
||||||
actions.className = 'admin-user-actions';
|
actions.className = 'admin-user-actions';
|
||||||
|
|
||||||
if (!isAdopted) {
|
// Recheck
|
||||||
// Recheck
|
var recheckBtn = document.createElement('button');
|
||||||
var recheckBtn = document.createElement('button');
|
recheckBtn.className = 'icon-btn';
|
||||||
recheckBtn.className = 'icon-btn';
|
recheckBtn.title = 'Erneut prüfen';
|
||||||
recheckBtn.title = 'Erneut prüfen';
|
recheckBtn.innerHTML = '<i class="fa fa-refresh"></i>';
|
||||||
recheckBtn.innerHTML = '<i class="fa fa-refresh"></i>';
|
recheckBtn.addEventListener('click', async function() {
|
||||||
recheckBtn.addEventListener('click', async function() {
|
recheckBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||||
recheckBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
recheckBtn.disabled = true;
|
||||||
recheckBtn.disabled = true;
|
try {
|
||||||
try {
|
await apiRecheckScannedKey(sk.scannedKeyId);
|
||||||
await apiRecheckScannedKey(sk.scannedKeyId);
|
await loadScannedKeys();
|
||||||
await loadScannedKeys();
|
} catch (err) { showToast(err.message, 'error'); }
|
||||||
} catch (err) { showToast(err.message, 'error'); }
|
finally { recheckBtn.innerHTML = '<i class="fa fa-refresh"></i>'; recheckBtn.disabled = false; }
|
||||||
finally { recheckBtn.innerHTML = '<i class="fa fa-refresh"></i>'; recheckBtn.disabled = false; }
|
});
|
||||||
});
|
actions.appendChild(recheckBtn);
|
||||||
actions.appendChild(recheckBtn);
|
|
||||||
|
|
||||||
// Übernehmen (bei valid oder quota_exceeded)
|
// Übernehmen (bei valid oder quota_exceeded)
|
||||||
if (sk.status === 'valid' || sk.status === 'quota_exceeded') {
|
if (sk.status === 'valid' || sk.status === 'quota_exceeded') {
|
||||||
var adoptBtn = document.createElement('button');
|
var adoptBtn = document.createElement('button');
|
||||||
adoptBtn.className = 'icon-btn';
|
adoptBtn.className = 'icon-btn';
|
||||||
adoptBtn.title = 'Als API-Key übernehmen';
|
adoptBtn.title = 'Als API-Key übernehmen';
|
||||||
adoptBtn.innerHTML = '<i class="fa fa-plus-circle" style="color:var(--accent)"></i>';
|
adoptBtn.innerHTML = '<i class="fa fa-plus-circle" style="color:var(--accent)"></i>';
|
||||||
adoptBtn.addEventListener('click', async function() {
|
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 = '<i class="fa fa-trash"></i>';
|
|
||||||
delBtn.addEventListener('click', async function() {
|
|
||||||
try {
|
try {
|
||||||
await apiDeleteScannedKey(sk.scannedKeyId);
|
await apiAdoptScannedKey(sk.scannedKeyId);
|
||||||
|
showToast('Key übernommen');
|
||||||
await loadScannedKeys();
|
await loadScannedKeys();
|
||||||
|
await loadKeys();
|
||||||
} catch (err) { showToast(err.message, 'error'); }
|
} 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 = '<i class="fa fa-trash"></i>';
|
||||||
|
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(info);
|
||||||
row.appendChild(actions);
|
row.appendChild(actions);
|
||||||
scannedList.appendChild(row);
|
scannedList.appendChild(row);
|
||||||
|
|||||||
Reference in new issue
Block a user