Skip to content

fix(providers): manage default provider safely - #810

Merged
Wibias merged 9 commits into
lidge-jun:devfrom
eachann1024:fix/provider-i18n-fallback
Jul 31, 2026
Merged

fix(providers): manage default provider safely#810
Wibias merged 9 commits into
lidge-jun:devfrom
eachann1024:fix/provider-i18n-fallback

Conversation

@eachann1024

@eachann1024 eachann1024 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a dashboard action to set an enabled provider as the default routing provider
  • safely reassign the default to the first remaining provider when its current provider is deleted; preserve the single-provider guard
  • localize provider mutation failures, success notices, and the default-provider delete confirmation in English, German, Korean, Simplified Chinese, Russian, and Japanese
  • prevent the hover-only rail delete control from partially covering the default star/status indicators
flowchart LR
  A["Set provider as default"] --> B["PATCH /api/providers?setDefault"]
  B --> C["Persist defaultProvider"]
  D["Delete current default"] --> E{"Another provider exists?"}
  E -- Yes --> F["Switch to first remaining provider"] --> G["Delete provider"]
  E -- No --> H["Keep config valid and show localized error"]
Loading

Validation

  • bun test tests/management-provider-validation.test.ts -t "switches the default"
  • bun test ./gui/tests/use-providers-crud-update.test.tsx ./gui/tests/rail-hover-delete.test.ts ./gui/tests/rail-hover-delete-dom.test.tsx
  • bun run lint / bun run lint:i18n / bun run build in gui/
  • bun run typecheck
  • bun run privacy:scan
  • Browser regression in an isolated local proxy: created a provider, set it as default, confirmed the Chinese fallback dialog, deleted it, and verified the first remaining provider became default with a localized success notice.

Notes

  • An independent locale review checked all six new translation sets, their terminology, and interpolation variables; its corrections are included.

Summary by CodeRabbit

  • New Features
    • Set an enabled provider as the default.
    • Automatically select a replacement when removing the current default.
    • Show replacement details in removal confirmations.
  • Bug Fixes
    • Prevent disabled providers from becoming default.
    • Prevent removal of the final enabled provider.
    • Improved localized error messages and dependent-combination validation.
  • Style
    • Improved provider list hover behavior around delete controls.
  • Documentation
    • Updated dashboard and API guidance for default-provider management.

@github-actions github-actions Bot added the bug Something isn't working label Jul 31, 2026
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The provider management API now supports default-provider selection, reassignment during deletion, and protection against deleting the final enabled provider. The GUI exposes these actions, localizes related errors, updates confirmation dialogs, documents the behavior, and adjusts rail hover styling.

Changes

Provider default management

Layer / File(s) Summary
Server default and deletion behavior
src/server/management/provider-routes.ts, gui/src/components/provider-workspace/types.ts, tests/management-provider-validation.test.ts
The API validates setDefault, supports standalone default updates, rejects disabled defaults, reassigns the default during deletion, and returns structured errors. Integration tests cover switching, reassignment, and rejection cases.
CRUD operations and localized errors
gui/src/pages/use-providers-crud.ts, gui/src/i18n/*.ts
useProvidersCrud exposes setDefaultProvider, refreshes configuration after success, and maps provider errors to localized notifications.
Provider workspace actions and confirmation
gui/src/components/provider-workspace/ProviderDetails.tsx, gui/src/components/provider-workspace/ProviderDialogs.tsx, gui/src/pages/Providers.tsx, gui/src/pages/providers-page-modals.tsx
Enabled non-default providers show “Set default”. Removal dialogs receive the replacement default name and use a specialized confirmation message when the current default is removed.
Workspace hover presentation
gui/src/styles/provider-workspace-shell.css, gui/tests/rail-hover-delete.test.ts
The rail hides trailing indicators while the delete control is visible. The test checks the zero-opacity state.
Provider management documentation
docs-site/src/content/docs/...
The dashboard and API documentation describe default assignment, automatic reassignment, enabled-provider restrictions, and the 409 last_provider response in supported languages.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProviderDetails
  participant Providers
  participant useProvidersCrud
  participant providerRoutes
  participant ProviderConfig
  ProviderDetails->>Providers: Select enabled non-default provider
  Providers->>useProvidersCrud: setDefaultProvider(name)
  useProvidersCrud->>providerRoutes: PATCH with setDefault: true
  providerRoutes->>ProviderConfig: Persist selected default
  ProviderConfig-->>providerRoutes: Return updated default
  providerRoutes-->>useProvidersCrud: Return success or structured error
  useProvidersCrud-->>Providers: Refresh configuration and notify result
Loading

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: wibias, ingwannu, lidge-jun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: safer default-provider management, including setting defaults and handling deletion reassignment.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gui/src/components/provider-workspace/types.ts`:
- Around line 89-90: Update ProviderUpdatePatch to use a discriminated union
with separate editable and standalone setDefault variants. Define the
setDefault: true variant with all other patch fields marked never, and define
the editable variant without setDefault and without apiKey. Preserve the
management route contract so setDefault requests cannot include additional
fields.

In `@gui/src/i18n/ko.ts`:
- Around line 313-316: Update the Korean locale entries prov.removedDefault,
prov.removeLastProvider, and prov.removeHasDependentCombos to use the existing
“프로바이더” terminology instead of “제공자”, including the additional affected entry,
while preserving the messages’ meaning and placeholders.

In `@gui/src/pages/Providers.tsx`:
- Line 347: Update the default-provider removal flow around
removeDefaultProvider to choose the first enabled remaining provider using fresh
server data, matching the server’s disabled-provider filtering rule rather than
relying on stale config.providers ordering. Reconcile the selected UI state with
the DELETE response, and add coverage for stale ordering and a disabled first
remaining provider.

In `@gui/tests/rail-hover-delete.test.ts`:
- Around line 80-83: Update the hover-style assertions in
rail-hover-delete.test.ts to use the existing rule() helper and verify that the
.pws-rail-row-wrap:hover .providers-workspace-rail-trail rule specifically
contains opacity: 0;. Do not use a stylesheet-wide opacity assertion that can
match unrelated declarations.

In `@src/server/management/provider-routes.ts`:
- Around line 437-466: Update the fallback selection in the provider deletion
flow around fallbackDefault to choose the first remaining provider whose
disabled flag is false or absent, matching the existing disabled-provider guard.
Reject deletion with a 409 conflict and the localized last-provider error code
when no enabled fallback remains, and add an integration test covering deletion
of the enabled provider while only a disabled provider remains.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe37f463-adf4-426c-96ec-936d72840085

📥 Commits

Reviewing files that changed from the base of the PR and between ee7c252 and 1cf32f5.

📒 Files selected for processing (16)
  • gui/src/components/provider-workspace/ProviderDetails.tsx
  • gui/src/components/provider-workspace/ProviderDialogs.tsx
  • gui/src/components/provider-workspace/types.ts
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/src/pages/Providers.tsx
  • gui/src/pages/providers-page-modals.tsx
  • gui/src/pages/use-providers-crud.ts
  • gui/src/styles/provider-workspace-shell.css
  • gui/tests/rail-hover-delete.test.ts
  • src/server/management/provider-routes.ts
  • tests/management-provider-validation.test.ts

Comment thread gui/src/components/provider-workspace/types.ts
Comment thread gui/src/i18n/ko.ts Outdated
Comment thread gui/src/pages/Providers.tsx Outdated
Comment thread gui/tests/rail-hover-delete.test.ts Outdated
Comment thread src/server/management/provider-routes.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1cf32f5689

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/management/provider-routes.ts
Comment thread gui/src/pages/use-providers-crud.ts Outdated
Comment thread gui/src/components/provider-workspace/ProviderDetails.tsx
Wibias added 2 commits July 31, 2026 11:53
DELETE of the current default now picks the first remaining enabled provider (or 409), matching setDefault/disable guards. Restore actionable API errors in the GUI and document the dashboard set-default flow.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
gui/src/i18n/zh.ts (1)

1322-1322: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the existing provider term in the workspace.

Nearby pws.* strings use 提供商, but this confirmation uses 提供方 twice. Replace both occurrences with 提供商 so the provider workspace uses one term.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gui/src/i18n/zh.ts` at line 1322, Update the pws.removeDefaultConfirmBody
translation in zh.ts by replacing both occurrences of 提供方 with 提供商, preserving
the existing placeholders and message structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/guides/web-dashboard.md`:
- Line 43: Update all eight documented sites to state that only enabled
providers may be selected as the default, and that deletion is refused when no
enabled replacement exists. In the English API sections, explicitly document the
enabled-only PATCH rule and the 409 response with code "last_provider", while
adding the equivalent dashboard and API behavior in Japanese, Korean, and
Russian at docs-site/src/content/docs/guides/web-dashboard.md:43-43 and 132-132,
docs-site/src/content/docs/ja/guides/web-dashboard.md:35-35 and 108-108,
docs-site/src/content/docs/ko/guides/web-dashboard.md:35-35 and 110-110, and
docs-site/src/content/docs/ru/guides/web-dashboard.md:35-35 and 114-114.

In `@docs-site/src/content/docs/zh-cn/guides/web-dashboard.md`:
- Line 34: Update both provider-management entries in
docs-site/src/content/docs/zh-cn/guides/web-dashboard.md at lines 34 and 102:
document that deleting the current default reassigns it to the first remaining
enabled provider, but deletion is refused and the current default is preserved
when no enabled replacement exists.

In `@tests/management-provider-validation.test.ts`:
- Around line 1003-1006: Remove the duplicate providers member from the response
type literal used by the saved assignment in the management-provider validation
test, keeping a single providers declaration with its existing Record<string, {
disabled?: boolean }> shape.

---

Outside diff comments:
In `@gui/src/i18n/zh.ts`:
- Line 1322: Update the pws.removeDefaultConfirmBody translation in zh.ts by
replacing both occurrences of 提供方 with 提供商, preserving the existing placeholders
and message structure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2f56b568-7f11-4ee2-99f7-e002524c3c65

📥 Commits

Reviewing files that changed from the base of the PR and between 1cf32f5 and dc6e92b.

📒 Files selected for processing (16)
  • docs-site/src/content/docs/guides/web-dashboard.md
  • docs-site/src/content/docs/ja/guides/web-dashboard.md
  • docs-site/src/content/docs/ko/guides/web-dashboard.md
  • docs-site/src/content/docs/ru/guides/web-dashboard.md
  • docs-site/src/content/docs/zh-cn/guides/web-dashboard.md
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/src/pages/Providers.tsx
  • gui/src/pages/use-providers-crud.ts
  • gui/tests/rail-hover-delete.test.ts
  • src/server/management/provider-routes.ts
  • tests/management-provider-validation.test.ts

Comment thread docs-site/src/content/docs/guides/web-dashboard.md Outdated
Comment thread docs-site/src/content/docs/zh-cn/guides/web-dashboard.md Outdated
Comment thread tests/management-provider-validation.test.ts
Clarify that set-default requires an enabled provider and that deleting the default is refused when no enabled replacement remains.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/guides/web-dashboard.md`:
- Line 132: Document the actual distinction between provider mutation paths: in
docs-site/src/content/docs/guides/web-dashboard.md:132-132,
docs-site/src/content/docs/ja/guides/web-dashboard.md:108-108,
docs-site/src/content/docs/ko/guides/web-dashboard.md:110-110,
docs-site/src/content/docs/ru/guides/web-dashboard.md:114-114, and
docs-site/src/content/docs/zh-cn/guides/web-dashboard.md:102-102, explain that
POST accepts setDefault alongside provider creation/replacement and PATCH uses
it as a standalone action, explicitly distinguishing enabled and disabled
provider behavior according to provider-routes.ts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 30bb4c73-0b70-4095-accf-fa1f24ff7245

📥 Commits

Reviewing files that changed from the base of the PR and between dc6e92b and 59a4038.

📒 Files selected for processing (5)
  • docs-site/src/content/docs/guides/web-dashboard.md
  • docs-site/src/content/docs/ja/guides/web-dashboard.md
  • docs-site/src/content/docs/ko/guides/web-dashboard.md
  • docs-site/src/content/docs/ru/guides/web-dashboard.md
  • docs-site/src/content/docs/zh-cn/guides/web-dashboard.md

Comment thread docs-site/src/content/docs/guides/web-dashboard.md Outdated
Match PATCH: refuse creating/replacing a disabled provider as default before mutating config, and document POST vs PATCH setDefault in the dashboard API table.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/server/management/provider-routes.ts`:
- Around line 121-123: Update the provider creation validation and
default-assignment checks to use strict boolean validation: require
body.setDefault === true rather than relying on truthiness, matching the PATCH
contract checks and rejecting values such as the string "false".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6dabcf12-f0ba-4bcd-98a8-392ec51a9035

📥 Commits

Reviewing files that changed from the base of the PR and between 59a4038 and 9b73667.

📒 Files selected for processing (7)
  • docs-site/src/content/docs/guides/web-dashboard.md
  • docs-site/src/content/docs/ja/guides/web-dashboard.md
  • docs-site/src/content/docs/ko/guides/web-dashboard.md
  • docs-site/src/content/docs/ru/guides/web-dashboard.md
  • docs-site/src/content/docs/zh-cn/guides/web-dashboard.md
  • src/server/management/provider-routes.ts
  • tests/management-provider-validation.test.ts

Comment thread src/server/management/provider-routes.ts Outdated
Wibias added 2 commits July 31, 2026 12:38
Reject non-boolean setDefault values and only promote when the flag is exactly true, matching the PATCH contract.
@Wibias

Wibias commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

[shipping-github] Verdict: approve-comment

PR: #810 — fix(providers): manage default provider safely
Head: 57a0968a on dev (mergeStateStatus: CLEAN)
Linked: none

Usefulness

Real dashboard gap: set an enabled provider as default, and delete the current default without a broken config. Fixes the prior “cannot delete default” / missing set-default UX, with six-locale notices and a rail hover polish so the delete control does not crop the default star.

Bugs / correctness

  • Checked: src/server/management/provider-routes.ts DELETE/PATCH/POST default flows; gui/src/pages/use-providers-crud.ts + confirm preview; focused bun test tests/management-provider-validation.test.ts (set-default / disabled-fallback / POST disabled setDefault) + bun run typecheck
  • Findings (fixed this session):
    • DELETE could reassign a disabled default → fixed in dc6e92b4 (enabled-only fallback or 409 last_provider)
    • GUI confirm preview matched the naive first-key pick → same commit
    • updateProvider / disable paths dropped actionable API errors → restored via apiErrorMessage
    • POST setDefault lacked the disabled + boolean guards → 9b736678 / 6d3990e0
  • Fixed this session: dc6e92b4, 59a4038e, 9b736678, 6d3990e0, merge 57a0968a

Security

  • Scope reviewed: management /api/providers PATCH/DELETE/POST, GUI CRUD, management auth/origin gate, disabled-default routing fail-closed
  • Findings: none medium+ (disabled-default reassignment was availability/consistency, now fixed)
  • Fixed this session: policy consistency on POST setDefault (enabled-only, before mutate)

Spec / standards

  • Spec source: PR body (no linked issue)
  • Gaps: none blocking; claimed set-default / delete-reassign / i18n / rail hover are present. Docs synced in docs-site web-dashboard (en + locales). Declined CodeRabbit discriminated-union rewrite of ProviderUpdatePatch (runtime already enforces standalone setDefault).

Reviews

  • Owners/maintainers: none open
  • Bots (CodeRabbit/Codex): cleared; declined type-union nit and false-positive duplicate providers cast; Korean terminology, hover test, docs, enabled-fallback, error preservation addressed

Base / CI

  • Behind/conflicts: updated in 57a0968a (merge from upstream/dev); clean
  • Required checks: green on 57a0968a (ubuntu/mac/windows + npm-global + enforce-target + react-doctor). Earlier Windows Bun crashes / unrelated Kiro timeouts on 6d3990e0 cleared after re-sync
  • Local tip compile/tests: bun run typecheck + focused provider-management tests — pass

Gate

none

Bottom line

Ship. Default-provider set/delete is correct against the enabled-provider invariant, localized, documented, and CI-clean on tip.

@Wibias

Wibias commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

[shipping-github] Merge ready

PR: #810 — fix(providers): manage default provider safely
Head: 57a0968adev (mergeStateStatus: CLEAN)
Linked issues: none

Reviews

  • Humans (owners first): none open
  • Bots: 0 unresolved useful threads; declined ProviderUpdatePatch discriminated-union rewrite (server already rejects combined setDefault patches); declined false-positive duplicate providers type member
  • Own bug + security + spec/standards: Bugbot + security-review + Spec/Standards done on tip; blockers fixed in dc6e92b46d3990e0

Tip freshness

  • Updated from dev: yes (57a0968a)
  • Compiles/tests against tip: bun run typecheck + focused management-provider-validation / GUI hover+CRUD tests — pass
  • Conflicts: none

Checks

  • Local/CLI: typecheck + provider default/delete regression tests green
  • Required CI: green on 57a0968a (flake retries on prior tip Windows Bun crash; cleared after tip sync)
  • Policy: review requests present; no unresolved threads; mergeable CLEAN

Residual

none for this PR. Optional later: rename removeDefaultProvider prop to fallbackDefaultProvider for clarity.

Ready to merge.

Wibias added 2 commits July 31, 2026 20:04
Cold Bun starts of `provider --help` exceeded the 5s default on contended windows-latest (status null). Use SPAWN_BUDGET_MS for the suite and give spawnSync a matching deadline.
@Wibias

Wibias commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Thanks @eachann1024 — merging this.

Why it helps: the Providers dashboard can now set an enabled provider as the default and delete the current default without leaving routing broken — provider-routes reassigns to the first remaining enabled provider (or refuses with last_provider), with localized notices and a rail hover fix so delete no longer crops the default star.

Ship it.

@Wibias
Wibias merged commit 5ddb14c into lidge-jun:dev Jul 31, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants