Add API key provisioning to accounts page
This commit is contained in:
+50
-1
@@ -493,7 +493,13 @@ fn account_css() -> String {
|
||||
.roadmap-items { list-style: none; display: flex; flex-direction: column; gap: .5rem; }
|
||||
.roadmap-items li { font-family: var(--body); font-size: .875rem; font-weight: 300; color: var(--t2); line-height: 1.6; padding-left: 1rem; position: relative; }
|
||||
.roadmap-items li::before { content: \"-\"; position: absolute; left: 0; color: var(--navy-65); }
|
||||
.signout-section { padding-top: 1rem; display: flex; justify-content: flex-end; }"
|
||||
.signout-section { padding-top: 1rem; display: flex; justify-content: flex-end; }
|
||||
.api-key-list { display: flex; flex-direction: column; gap: 1rem; }
|
||||
.api-key-row { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
|
||||
.api-key-provider { display: flex; flex-direction: column; gap: .2rem; min-width: 120px; }
|
||||
.api-key-name { font-size: .875rem; font-weight: 500; color: var(--t1); }
|
||||
.api-key-masked { font-size: .75rem; font-family: monospace; color: var(--t3); }
|
||||
.api-key-actions { display: flex; gap: .5rem; }"
|
||||
"<style>" + css + "</style>"
|
||||
}
|
||||
|
||||
@@ -804,6 +810,48 @@ fn account_devices_card() -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn api_key_provider_row(provider_id: String, provider_name: String, placeholder: String) -> String {
|
||||
el_div(
|
||||
"class=\"api-key-row\"",
|
||||
el_div(
|
||||
"class=\"api-key-provider\"",
|
||||
el_span("class=\"api-key-name\"", provider_name) +
|
||||
el_span("class=\"api-key-masked\" id=\"apikey-masked-" + provider_id + "\"", "Not configured")
|
||||
) +
|
||||
"<input type=\"password\" id=\"apikey-input-" + provider_id + "\" class=\"acct-input\" placeholder=\"" + placeholder + "\" autocomplete=\"off\" style=\"margin-bottom:0;flex:1\">" +
|
||||
el_div(
|
||||
"class=\"api-key-actions\"",
|
||||
el_button("type=\"button\" class=\"btn-primary\" style=\"padding:.5rem 1rem;font-size:.75rem\" onclick=\"saveApiKey('" + provider_id + "')\"", "Save") +
|
||||
el_button("type=\"button\" class=\"btn-ghost\" style=\"padding:.5rem 1rem;font-size:.75rem;display:none\" id=\"apikey-del-" + provider_id + "\" onclick=\"deleteApiKey('" + provider_id + "')\"", "Remove")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn account_api_keys_section() -> String {
|
||||
let providers: String = el_div(
|
||||
"class=\"api-key-list\"",
|
||||
api_key_provider_row("openai", "OpenAI", "sk-...") +
|
||||
api_key_provider_row("anthropic", "Anthropic", "sk-ant-...") +
|
||||
api_key_provider_row("gemini", "Gemini", "AIza...") +
|
||||
api_key_provider_row("grok", "Grok", "xai-...")
|
||||
)
|
||||
el_div(
|
||||
"id=\"api-keys-section\" style=\"display:none\"",
|
||||
el_div(
|
||||
"class=\"card-dark\"",
|
||||
el_div(
|
||||
"class=\"acct-section-header\"",
|
||||
el_p("class=\"card-label\"", "API Keys") +
|
||||
el_p("style=\"font-size:.8125rem;font-weight:300;color:var(--t2);line-height:1.65\"",
|
||||
"Add your own AI provider keys. Neuron uses them directly — your keys, your models, your data."
|
||||
)
|
||||
) +
|
||||
providers +
|
||||
el_p("id=\"api-keys-msg\" style=\"display:none;font-size:.8rem;margin-top:.75rem\"", "")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn account_dashboard_section() -> String {
|
||||
let header_row: String = el_div(
|
||||
"class=\"acct-header-row\"",
|
||||
@@ -828,6 +876,7 @@ fn account_dashboard_section() -> String {
|
||||
el_div(
|
||||
"class=\"account-section\"",
|
||||
account_plan_card() +
|
||||
account_api_keys_section() +
|
||||
account_roadmap_section() +
|
||||
account_family_section() +
|
||||
account_badge_section() +
|
||||
|
||||
Reference in New Issue
Block a user