Skip to content
19 changes: 19 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ fn canonical_provider_arg(provider_id: &str) -> Result<String, String> {
Ok(parse_provider_arg(provider_id)?.cli_name().to_string())
}

fn provider_dashboard_url(id: ProviderId, settings: &Settings) -> Option<String> {
match id {
ProviderId::MiniMax => Some(
codexbar::providers::MiniMaxProvider::dashboard_url_for_region(Some(
settings.api_region(id),
)),
),
ProviderId::Kimi => Some(
codexbar::providers::KimiRegion::from_settings(Some(settings.api_region(id)))
.console_url()
.to_string(),
),
_ => instantiate_provider(id)
.metadata()
.dashboard_url
.map(str::to_string),
}
}

fn validate_single_line_secret(value: &str, field: &str, max_len: usize) -> Result<(), String> {
let trimmed = value.trim();
if trimmed.is_empty() {
Expand Down
10 changes: 1 addition & 9 deletions apps/desktop-tauri/src-tauri/src/commands/provider_detail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,7 @@ pub(crate) fn build_provider_detail(
let provider = instantiate_provider(id);
let metadata = provider.metadata();
let resume_supported = auto_resume_supported(id);
let dashboard_url = if id == codexbar::core::ProviderId::MiniMax {
Some(
codexbar::providers::MiniMaxProvider::dashboard_url_for_region(Some(
settings.api_region(id),
)),
)
} else {
metadata.dashboard_url.map(|s| s.to_string())
};
let dashboard_url = provider_dashboard_url(id, &settings);

let detail = ProviderDetail {
id: id.cli_name().to_string(),
Expand Down
13 changes: 13 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ fn region_provider(provider_id: &str) -> Option<codexbar::core::ProviderId> {
"alibabatokenplan" => ProviderId::AlibabaTokenPlan,
"zai" => ProviderId::Zai,
"minimax" => ProviderId::MiniMax,
"kimi" => ProviderId::Kimi,
_ => return None,
})
}
Expand All @@ -282,6 +283,10 @@ pub(crate) fn provider_region_lookup(settings: &Settings, provider_id: &str) ->
))
.settings_value()
.to_string()
} else if id == codexbar::core::ProviderId::Kimi {
codexbar::providers::KimiRegion::from_settings(Some(settings.api_region(id)))
.settings_value()
.to_string()
} else {
settings.api_region(id).to_string()
}
Expand Down Expand Up @@ -784,6 +789,14 @@ pub fn region_options_for(provider_id: &str) -> Vec<RegionOption> {
.to_string(),
},
],
"kimi" => codexbar::providers::KimiRegion::ALL
.iter()
.copied()
.map(|region| RegionOption {
value: region.settings_value().to_string(),
label: region.display_name().to_string(),
})
.collect(),
"alibabatokenplan" => codexbar::providers::AlibabaTokenPlanRegion::ALL
.iter()
.copied()
Expand Down
31 changes: 2 additions & 29 deletions apps/desktop-tauri/src-tauri/src/commands/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,36 +205,9 @@ pub fn quit_app(app: tauri::AppHandle) {
}

fn dashboard_url_for_provider(provider_id: &str) -> Option<String> {
if provider_id == ProviderId::MiniMax.cli_name() {
let settings = Settings::load();
return Some(
codexbar::providers::MiniMaxProvider::dashboard_url_for_region(Some(
settings.api_region(ProviderId::MiniMax),
)),
);
}

// OpenRouter's Usage Dashboard is the Activity page. Resolve it from the
// provider metadata before the legacy API-key catalog entry, which still
// points at the credits settings page.
if provider_id == ProviderId::OpenRouter.cli_name() {
return instantiate_provider(ProviderId::OpenRouter)
.metadata()
.dashboard_url
.map(|s| s.to_string());
}

if let Some(url) = codexbar::settings::get_api_key_providers()
.into_iter()
.find(|p| p.id.cli_name() == provider_id)
.and_then(|p| p.dashboard_url.map(|s| s.to_string()))
{
return Some(url);
}

let id = ProviderId::from_cli_name(provider_id)?;
let provider = instantiate_provider(id);
provider.metadata().dashboard_url.map(|s| s.to_string())
let settings = Settings::load();
provider_dashboard_url(id, &settings)
}

fn status_page_url_for_provider(provider_id: &str) -> Option<String> {
Expand Down
37 changes: 37 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,20 @@ fn minimax_region_lookup_normalizes_legacy_china_value() {
assert_eq!(provider_region_lookup(&s, "minimax").as_deref(), Some("cn"));
}

#[test]
fn kimi_region_lookup_defaults_to_china_and_roundtrips_international() {
let mut settings = Settings::default();
assert_eq!(
provider_region_lookup(&settings, "kimi").as_deref(),
Some("china")
);
super::provider_region_set(&mut settings, "kimi", "international".to_string()).unwrap();
assert_eq!(
provider_region_lookup(&settings, "kimi").as_deref(),
Some("international")
);
}

#[test]
fn minimax_cookie_domain_follows_selected_region() {
let mut s = Settings::default();
Expand Down Expand Up @@ -690,6 +704,22 @@ fn fetch_context_includes_minimax_region() {
assert_eq!(ctx.api_region.as_deref(), Some("cn"));
}

#[test]
fn provider_dashboard_url_uses_selected_regional_console() {
let mut settings = Settings::default();
settings.set_api_region(ProviderId::MiniMax, "cn");
settings.set_api_region(ProviderId::Kimi, "international");

assert_eq!(
super::provider_dashboard_url(ProviderId::MiniMax, &settings).as_deref(),
Some("https://platform.minimaxi.com/user-center/payment/coding-plan?cycle_type=3")
);
assert_eq!(
super::provider_dashboard_url(ProviderId::Kimi, &settings).as_deref(),
Some("https://www.kimi.ai/code/console")
);
}

#[test]
fn fetch_context_token_account_uses_web_cookie_header() {
let settings = Settings::default();
Expand Down Expand Up @@ -1824,6 +1854,13 @@ fn minimax_region_options_match_upstream_hosts() {
);
}

#[test]
fn kimi_region_options_match_regional_hosts() {
let opts = super::region_options_for("kimi");
let values: Vec<_> = opts.iter().map(|option| option.value.as_str()).collect();
assert_eq!(values, vec!["china", "international"]);
}

#[test]
fn region_options_empty_for_non_regional_provider() {
assert!(super::region_options_for("claude").is_empty());
Expand Down
19 changes: 14 additions & 5 deletions apps/desktop-tauri/src/hooks/useTrayPanelLayout.sizing.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,20 @@ describe("useTrayPanelLayout sizing", () => {
tauriMocks.revealTrayPanelWindow.mock.calls.length;
expect(settledRevealCount - revealsBeforeSettle).toBeLessThanOrEqual(1);

await act(async () => {
await new Promise((resolve) => window.setTimeout(resolve, 500));
});
expect(tauriMocks.revealTrayPanelWindow.mock.calls.length).toBe(
settledRevealCount,
let lastRevealCount = settledRevealCount;
let stableSince = Date.now();
await waitFor(
() => {
const revealCount =
tauriMocks.revealTrayPanelWindow.mock.calls.length;
if (revealCount !== lastRevealCount) {
lastRevealCount = revealCount;
stableSince = Date.now();
}
expect(revealCount - revealsBeforeSettle).toBeLessThanOrEqual(1);
expect(Date.now() - stableSince).toBeGreaterThanOrEqual(500);
},
{ timeout: 3000, interval: 50 },
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface Props {
}

/**
* API-region dropdown for Alibaba / Z.ai / MiniMax.
* API-region dropdown for providers with regional endpoints, including Kimi.
*
* Port of the region ComboBox rows in
* `rust/src/native_ui/preferences.rs::render_provider_detail_panel`.
Expand Down
Loading