fix(web): providers page reported a missing API key for every provider
Nightly Build / build (push) Successful in 4m35s

The card tested `p.api_key` on a DTO that has never carried it, so the badge
was falsy for every provider and always read "API key missing".

The list and the new detail DTO now expose `has_api_key: bool` — the key
value itself never reaches the browser, where the edit form used to prefill
it in plain text. Since the form can no longer send the stored key back, an
empty `api_key` on update means "keep the one on file" instead of erasing it,
which is what the field's placeholder already promised.
This commit is contained in:
Daniele
2026-09-01 21:01:45 +01:00
parent c1a8227e11
commit 65e0f24326
6 changed files with 69 additions and 8 deletions
+39 -3
View File
@@ -98,12 +98,43 @@ pub async fn create_provider(
Ok(StatusCode::CREATED)
}
/// One provider, as the edit form sees it. Deliberately **not** `LlmProviderRecord`:
/// the stored api_key never travels to the browser — the form only needs to know
/// whether one exists, so it can offer "leave blank to keep it".
#[derive(Serialize)]
pub struct ProviderDetail {
pub id: i64,
pub name: String,
#[serde(rename = "type")]
pub provider: String,
pub has_api_key: bool,
pub base_url: Option<String>,
pub description: Option<String>,
}
impl From<LlmProviderRecord> for ProviderDetail {
fn from(r: LlmProviderRecord) -> Self {
ProviderDetail {
id: r.id,
name: r.name,
provider: r.provider,
has_api_key: has_key(&r.api_key),
base_url: r.base_url,
description: r.description,
}
}
}
fn has_key(key: &Option<String>) -> bool {
key.as_deref().is_some_and(|k| !k.trim().is_empty())
}
pub async fn get_provider(
State(skald): State<Arc<Skald>>,
axum::extract::Path(id): axum::extract::Path<i64>,
) -> Result<Json<LlmProviderRecord>, ApiError> {
) -> Result<Json<ProviderDetail>, ApiError> {
skald.llm_manager().get_provider(id).await
.map(Json)
.map(|r| Json(ProviderDetail::from(r)))
.ok_or_else(|| ApiError::not_found(format!("provider {id} not found")))
}
@@ -113,7 +144,12 @@ pub async fn update_provider(
Json(payload): Json<ProviderPayload>,
) -> Result<StatusCode, ApiError> {
validate_provider_type(&skald, &payload.provider)?;
let record = LlmProviderRecord::from(payload);
let mut record = LlmProviderRecord::from(payload);
// The form never receives the stored key, so it cannot send it back: an empty
// api_key means "keep the one on file", not "erase it".
if !has_key(&record.api_key) {
record.api_key = skald.llm_manager().get_provider(id).await.and_then(|r| r.api_key);
}
skald.llm_manager().update_provider(id, record).await?;
Ok(StatusCode::NO_CONTENT)
}