fix(admin): preserve inactive endpoint key counts

This commit is contained in:
MMEXA
2026-07-12 04:19:06 +08:00
parent 63936aa110
commit 02495ce28e
+56 -8
View File
@@ -46,15 +46,21 @@ pub fn key_api_formats_without_entry(
)
}
fn active_endpoint_api_formats(endpoints: &[StoredProviderCatalogEndpoint]) -> Vec<String> {
let mut formats = Vec::new();
for endpoint in endpoints.iter().filter(|endpoint| endpoint.is_active) {
fn endpoint_api_format_sets(
endpoints: &[StoredProviderCatalogEndpoint],
) -> (Vec<String>, Vec<String>) {
let mut all = Vec::new();
let mut active = Vec::new();
for endpoint in endpoints {
let api_format = normalize_endpoint_api_format(&endpoint.api_format);
if !formats.iter().any(|existing| existing == &api_format) {
formats.push(api_format);
if !all.iter().any(|existing| existing == &api_format) {
all.push(api_format.clone());
}
if endpoint.is_active && !active.iter().any(|existing| existing == &api_format) {
active.push(api_format);
}
}
formats
(all, active)
}
fn configured_key_api_formats(key: &StoredProviderCatalogKey) -> Vec<String> {
@@ -82,7 +88,7 @@ pub fn endpoint_key_counts_by_format(
) -> (BTreeMap<String, usize>, BTreeMap<String, usize>) {
let mut total = BTreeMap::new();
let mut active = BTreeMap::new();
let endpoint_api_formats = active_endpoint_api_formats(endpoints);
let (endpoint_api_formats, active_endpoint_api_formats) = endpoint_api_format_sets(endpoints);
for key in keys {
let inherits_api_formats = fixed_provider_key_inherits_api_formats(
@@ -96,7 +102,12 @@ pub fn endpoint_key_counts_by_format(
.is_none_or(serde_json::Value::is_null);
let configured_api_formats = configured_key_api_formats(key);
for api_format in endpoint_api_formats.iter().filter(|api_format| {
let candidate_api_formats = if inherits_api_formats {
&active_endpoint_api_formats
} else {
&endpoint_api_formats
};
for api_format in candidate_api_formats.iter().filter(|api_format| {
inherits_api_formats
|| has_unrestricted_api_format_scope
|| configured_api_formats.iter().any(|allowed| {
@@ -163,6 +174,43 @@ mod endpoint_key_count_tests {
assert_eq!(total.get("openai:search"), Some(&3));
assert_eq!(active, total);
}
#[test]
fn endpoint_counts_keep_scoped_keys_visible_on_inactive_endpoints() {
let mut endpoint = sample_endpoint("chat", "openai:chat");
endpoint.is_active = false;
let mut empty_scope_key = sample_key("empty-scope-key", None);
empty_scope_key.api_formats = Some(json!([]));
let keys = vec![
sample_key("chat-key", Some("openai:chat")),
sample_key("unrestricted-key", None),
empty_scope_key,
];
let (total, active) = endpoint_key_counts_by_format("custom", &[endpoint], &keys);
assert_eq!(total.get("openai:chat"), Some(&2));
assert_eq!(active, total);
}
#[test]
fn inherited_endpoint_counts_only_include_active_formats() {
let responses_endpoint = sample_endpoint("responses", "openai:responses");
let mut search_endpoint = sample_endpoint("search", "openai:search");
search_endpoint.is_active = false;
let mut inherited_key = sample_key("codex-key", Some("legacy:mismatch"));
inherited_key.auth_type = "oauth".to_string();
let (total, active) = endpoint_key_counts_by_format(
"codex",
&[responses_endpoint, search_endpoint],
&[inherited_key],
);
assert_eq!(total.get("openai:responses"), Some(&1));
assert!(!total.contains_key("openai:search"));
assert_eq!(active, total);
}
}
fn masked_proxy_value(proxy: Option<&serde_json::Value>) -> serde_json::Value {