Skip to content

feat(providers): manual "Clear cooldown" action in the cooling panel - #12224

Merged
diegosouzapw merged 4 commits into
diegosouzapw:release/v3.8.51from
patrykkopycinski:feat/clear-cooldown-button
Sep 1, 2026
Merged

diegosouzapw merged 4 commits into
diegosouzapw:release/v3.8.51from
patrykkopycinski:feat/clear-cooldown-button

Conversation

@patrykkopycinski

Copy link
Copy Markdown
Contributor

Summary

Adds a per-row "Clear cooldown" button to the Currently cooling panel on the provider detail page, for the case where the quota has already refreshed upstream but OmniRoute still benches the connection — the persisted rate_limited_until is OmniRoute's local lesson from the last 429, not upstream truth.

Problem

The cooldown survives process restarts by design (per-account 429 cascade fix). Until it expires, the connection is skipped by routing — even if the provider quota reset minutes ago. The only existing clear paths are side effects of a successful upstream round-trip:

  • Test button (buildCredentialTestStatusUpdate) — clears on success, but preserves scheduled quota windows by design
  • Edit modal → re-enter API key — clears only when a key is re-typed and validates

Both demand an upstream round-trip, so the "quota already reset" case had no UI remedy; the user waits out a stale local bench.

Solution

A dedicated, direct action:

  • PUT /api/providers/:id with { rateLimitedUntil: null } — first-class in updateProviderConnectionSchema, and the route applies the same defaults that reset backoffLevel → 0
  • Optimistic local drop (row leaves the cooling panel immediately), success/error toast, full refetch to reconcile with server truth
  • The next request is the real test of the key — if the quota is still exhausted, the 429 handler re-benches it with a fresh timer

Changes

File Change
useProviderConnections.ts handleClearCooldown + clearingCooldownId in-flight guard (mirrors retestingId pattern)
CoolingConnectionsPanel.tsx optional onClearCooldown / clearingCooldownId props; button hidden for id-less rows, disabled per-row while clearing
ProviderDetailPageClient.tsx Wires the handler + in-flight id through to the panel
en.json clearCooldown, clearCooldownInProgress, clearCooldownTitle, cooldownCleared, failedClearCooldown (with providerText fallbacks, so no hard i18n dependency)

Verification

  • npm run typecheck:core — clean
  • ESLint on all four touched source files — clean (the two remaining no-unused-vars hits in the tree are pre-existing on base, untouched lines)
  • New CoolingConnectionsPanel.test.tsx — 6/6 green (click → handler with row id; disabled + silent while in flight; per-row independence; read-only when handler omitted; no button without connection id; renders nothing when empty)
  • Pre-existing tests/unit/ui/CoolingConnectionsPanel.test.tsx — still 3/3 green
  • API behavior (PUT {rateLimitedUntil: null} → cooldown + backoff cleared) verified live against a running instance before implementation

Not in scope

  • Server-side changes: none. The PUT route already accepts the field; this is purely UI wiring.
  • Scheduled quota windows (Kimi weekly, Claude session): intentionally not auto-cleared by this button either — the PUT only clears the persisted cooldown field, it does not override shouldPreserveScheduledQuotaCooldown semantics on the test path.

The persisted 429 cooldown (provider_connections.rate_limited_until) is
OmniRoute's local lesson, not upstream truth. When a quota has already
refreshed upstream (daily/weekly reset, provider-side fix), the only
automatic clear paths — Test-button success or Edit-modal key
re-validation — still require an upstream round-trip, so the user waits
out a bench that is already stale.

Adds a per-row "Clear cooldown" button to CoolingConnectionsPanel that
PUTs rateLimitedUntil: null (the route applies backoff reset defaults),
optimistically drops the bench, and refetches. The next request becomes
the real test of the key.

- useProviderConnections: handleClearCooldown + clearingCooldownId
  (in-flight guard mirrors the retestingId pattern)
- CoolingConnectionsPanel: optional onClearCooldown/clearingCooldownId
  props; button hidden for id-less rows, disabled per-row while clearing
- ProviderDetailPageClient: wires the new handler through
- i18n: en.json keys (clearCooldown, cooldownCleared,
  failedClearCooldown, ...) with providerText fallbacks

Tests: CoolingConnectionsPanel.test.tsx — click fires handler with the
row id, disabled + silent while in flight, per-row independence,
read-only when handler omitted, no button without connection id,
renders nothing when empty. Pre-existing
tests/unit/ui/CoolingConnectionsPanel.test.tsx stays green.
…utton

The providers namespace already carried an (orphaned) clearCooldown /
cooldownCleared / failedClearCooldown key trio, so the new feature keys
re-declared them as duplicate JSON keys ~1200 lines apart. JSON.parse is
last-wins, which silently shadowed the older values and broke ICU
placeholder parity in every locale (EN lost {model} while all 42
translations still carry it). Rename the feature's five keys to a
connection-scoped family instead:

  clearConnectionCooldown / clearConnectionCooldownInProgress /
  clearConnectionCooldownTitle / connectionCooldownCleared /
  failedClearConnectionCooldown

Also extract the per-row action into ClearCooldownButton so the panel
body stays inside the max-lines-per-function ratchet (was 83/80).
Adds the five connection-cooldown keys to every non-EN catalog with the
English value as the runtime fallback (fill-missing-from-en semantics),
and real translations for pt-BR and vi so their strict parity suites
stay meaningful:

  pt-BR: Limpar cooldown / Limpando… / Cooldown limpo — a conexão voltou
         ao roteamento / Falha ao limpar cooldown
  vi:    Xóa thời gian chờ / Đang xóa… / Đã xóa thời gian chờ — kết nối
         đã tham gia lại định tuyến / Không thể xóa thời gian chờ
@diegosouzapw
diegosouzapw merged commit 438db55 into diegosouzapw:release/v3.8.51 Sep 1, 2026
16 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…iegosouzapw#12224)

* feat(providers): manual "Clear cooldown" action in the cooling panel

The persisted 429 cooldown (provider_connections.rate_limited_until) is
OmniRoute's local lesson, not upstream truth. When a quota has already
refreshed upstream (daily/weekly reset, provider-side fix), the only
automatic clear paths — Test-button success or Edit-modal key
re-validation — still require an upstream round-trip, so the user waits
out a bench that is already stale.

Adds a per-row "Clear cooldown" button to CoolingConnectionsPanel that
PUTs rateLimitedUntil: null (the route applies backoff reset defaults),
optimistically drops the bench, and refetches. The next request becomes
the real test of the key.

- useProviderConnections: handleClearCooldown + clearingCooldownId
  (in-flight guard mirrors the retestingId pattern)
- CoolingConnectionsPanel: optional onClearCooldown/clearingCooldownId
  props; button hidden for id-less rows, disabled per-row while clearing
- ProviderDetailPageClient: wires the new handler through
- i18n: en.json keys (clearCooldown, cooldownCleared,
  failedClearCooldown, ...) with providerText fallbacks

Tests: CoolingConnectionsPanel.test.tsx — click fires handler with the
row id, disabled + silent while in flight, per-row independence,
read-only when handler omitted, no button without connection id,
renders nothing when empty. Pre-existing
tests/unit/ui/CoolingConnectionsPanel.test.tsx stays green.

* fix(dashboard): dedupe clear-cooldown i18n keys and extract the row button

The providers namespace already carried an (orphaned) clearCooldown /
cooldownCleared / failedClearCooldown key trio, so the new feature keys
re-declared them as duplicate JSON keys ~1200 lines apart. JSON.parse is
last-wins, which silently shadowed the older values and broke ICU
placeholder parity in every locale (EN lost {model} while all 42
translations still carry it). Rename the feature's five keys to a
connection-scoped family instead:

  clearConnectionCooldown / clearConnectionCooldownInProgress /
  clearConnectionCooldownTitle / connectionCooldownCleared /
  failedClearConnectionCooldown

Also extract the per-row action into ClearCooldownButton so the panel
body stays inside the max-lines-per-function ratchet (was 83/80).

* feat(dashboard): mirror the clear-cooldown keys into all 42 locales

Adds the five connection-cooldown keys to every non-EN catalog with the
English value as the runtime fallback (fill-missing-from-en semantics),
and real translations for pt-BR and vi so their strict parity suites
stay meaningful:

  pt-BR: Limpar cooldown / Limpando… / Cooldown limpo — a conexão voltou
         ao roteamento / Falha ao limpar cooldown
  vi:    Xóa thời gian chờ / Đang xóa… / Đã xóa thời gian chờ — kết nối
         đã tham gia lại định tuyến / Không thể xóa thời gian chờ

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants