fix: rename API Keys -> Sub-Keys, show key inline on creation, no reload
This commit is contained in:
parent
ab4f60e159
commit
c684d96d90
|
|
@ -192,8 +192,8 @@ export const account = new Elysia({ prefix: "/account" })
|
|||
const keyLookup = sha256(norm);
|
||||
const keyHash = await Bun.password.hash(norm, { algorithm: "bcrypt", cost: 10 });
|
||||
|
||||
await sql`INSERT INTO api_keys (key_lookup, key_hash, account_id, label) VALUES (${keyLookup}, ${keyHash}, ${accountId}, ${body.label})`;
|
||||
return { key: rawKey, label: body.label };
|
||||
const [created] = await sql`INSERT INTO api_keys (key_lookup, key_hash, account_id, label) VALUES (${keyLookup}, ${keyHash}, ${accountId}, ${body.label}) RETURNING id`;
|
||||
return { key: rawKey, id: created.id, label: body.label };
|
||||
}, {
|
||||
body: t.Object({
|
||||
label: t.String({ description: "A name for this key, e.g. 'ci-pipeline' or 'mobile-app'" }),
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@
|
|||
<section class="bg-gray-900 rounded-xl border border-gray-800 p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h2 class="text-sm font-semibold text-gray-300">API Keys</h2>
|
||||
<h2 class="text-sm font-semibold text-gray-300">Sub-Keys</h2>
|
||||
<p class="text-xs text-gray-600 mt-0.5">Create separate keys for different apps, scripts, or teammates.</p>
|
||||
</div>
|
||||
<button onclick="showCreateKey()" class="px-3 py-1.5 bg-blue-600 hover:bg-blue-500 text-white rounded-lg text-xs font-medium transition-colors">+ New Key</button>
|
||||
<button onclick="showCreateKey()" class="px-3 py-1.5 bg-blue-600 hover:bg-blue-500 text-white rounded-lg text-xs font-medium transition-colors">+ New Sub-Key</button>
|
||||
</div>
|
||||
|
||||
<!-- Create key form (hidden by default) -->
|
||||
|
|
@ -66,19 +66,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- New key reveal (shown after creation) -->
|
||||
<!-- New sub-key reveal (shown after creation) -->
|
||||
<div id="new-key-reveal" class="hidden mb-4 p-4 bg-green-950/30 rounded-lg border border-green-900/50">
|
||||
<p class="text-xs text-green-400 mb-2">Key created — copy it now.</p>
|
||||
<p class="text-xs text-green-400 mb-2">Sub-key created — copy it now, it won't be shown again.</p>
|
||||
<div class="flex gap-2">
|
||||
<code id="new-key-value" class="flex-1 bg-gray-900 border border-gray-800 rounded-lg px-3 py-2 text-blue-400 text-sm tracking-widest"></code>
|
||||
<code id="new-key-value" class="flex-1 bg-gray-900 border border-gray-800 rounded-lg px-3 py-2 text-blue-400 text-sm font-mono select-all"></code>
|
||||
<button onclick="copyNewKey()" class="px-3 bg-gray-800 hover:bg-gray-700 border border-gray-700 rounded-lg text-gray-400 hover:text-white text-xs transition-colors">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Keys list -->
|
||||
<!-- Sub-keys list -->
|
||||
<div id="keys-list" class="space-y-2">
|
||||
<% if (it.apiKeys.length === 0) { %>
|
||||
<p class="text-xs text-gray-600 italic">No API keys yet.</p>
|
||||
<p class="text-xs text-gray-600 italic">No sub-keys yet.</p>
|
||||
<% } else { %>
|
||||
<% it.apiKeys.forEach(function(k) { %>
|
||||
<div class="flex items-center justify-between p-3 bg-gray-800/50 rounded-lg border border-gray-700/50">
|
||||
|
|
@ -97,15 +97,7 @@
|
|||
|
||||
|
||||
<script>
|
||||
// On load: check sessionStorage for a newly created key to reveal
|
||||
(function() {
|
||||
const newKey = sessionStorage.getItem('_newApiKey');
|
||||
if (newKey) {
|
||||
sessionStorage.removeItem('_newApiKey');
|
||||
document.getElementById('new-key-value').textContent = newKey;
|
||||
document.getElementById('new-key-reveal').classList.remove('hidden');
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
async function saveEmail() {
|
||||
const email = document.getElementById('email-input').value.trim();
|
||||
|
|
@ -152,8 +144,17 @@
|
|||
const label = document.getElementById('key-label').value.trim();
|
||||
if (!label) return;
|
||||
const data = await api('/account/keys', { method: 'POST', body: { label } });
|
||||
sessionStorage.setItem('_newApiKey', data.key);
|
||||
location.reload();
|
||||
hideCreateKey();
|
||||
document.getElementById('new-key-value').textContent = data.key;
|
||||
document.getElementById('new-key-reveal').classList.remove('hidden');
|
||||
// Add to list without reload
|
||||
const list = document.getElementById('keys-list');
|
||||
const empty = list.querySelector('p.italic');
|
||||
if (empty) empty.remove();
|
||||
const item = document.createElement('div');
|
||||
item.className = 'flex items-center justify-between p-3 bg-gray-800/50 rounded-lg border border-gray-700/50';
|
||||
item.innerHTML = `<div><p class="text-sm text-gray-200">${label}</p><p class="text-xs text-gray-600 mt-0.5">just now · never used</p></div><button onclick="deleteKey('${data.id}')" class="text-xs text-gray-600 hover:text-red-400 transition-colors px-2 py-1">Revoke</button>`;
|
||||
list.appendChild(item);
|
||||
}
|
||||
|
||||
function copyNewKey() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue