Skip to content

feat(desktop): simplify provider cards in Settings → API 服务#116

Closed
hqhq1025 wants to merge 2 commits intowt/unify-api-configfrom
wt/settings-ui-simplify
Closed

feat(desktop): simplify provider cards in Settings → API 服务#116
hqhq1025 wants to merge 2 commits intowt/unify-api-configfrom
wt/settings-ui-simplify

Conversation

@hqhq1025
Copy link
Copy Markdown
Collaborator

Summary

Cleans up the Settings → API 服务 provider list now that PR #113 has dropped modelFast and unified the API config IPC.

Before

After

  • Card collapses to one header row: label + masked key + optional base URL on the left; "当前" badge OR a compact "设为当前" button + a ··· overflow menu on the right.
  • Active provider: the model is rendered as a click-to-edit chip (clicking swaps in an inline NativeSelect that commits + closes on change). Non-active providers: no model selector at all.
  • Overflow menu items: Test connection (active card only — wired to existing connection.testActive IPC and toasts the result), Re-enter key, Delete (with inline confirm/cancel inside the menu, replacing the always-visible trash button + confirm row).
  • The duplicated dashed "+ 添加服务" button at the bottom of the list is removed; the secondary Plus button in the section header is the single entry point.
  • Click-outside dismisses the overflow menu.
  • New i18n keys (zh-CN + en): settings.providers.delete, testConnection, moreActions, editModel, toast.connectionOk, toast.connectionFailed. All existing keys are preserved.

Behavior changes

  • Non-active providers no longer show a model selector (they cannot affect generation).
  • Active model save is now immediate on <select> change instead of debounced — the chip closes back to read-only after each commit, so debouncing is unnecessary.
  • "Test connection" is now reachable from the provider card (was previously only available during onboarding).
  • Delete confirmation lives inside the overflow menu instead of expanding into the card row.

Constraints respected

  • No IPC changes; only re-uses setProviderAndModels, setActiveProvider, connection.testActive, deleteProvider.
  • No new dependencies. Only lucide-react icons (already in deps): added MoreHorizontal, KeyRound, removed unused Zap.
  • All colors / spacing via packages/ui CSS variables.
  • AddProviderModal cognitive complexity unchanged (still 16, was warned at 16 pre-change).
  • Compatibility ✅ · Upgradeability ✅ · No bloat ✅ · Elegance ✅

Test plan

  • pnpm --filter @open-codesign/desktop typecheck — clean
  • pnpm --filter @open-codesign/desktop test — 337/337 pass (no count delta)
  • pnpm exec biome check apps/desktop/src/renderer/src/components/Settings.tsx — only the pre-existing complexity-16 warning on AddProviderModal
  • Manual smoke (reviewer): add provider → see new card layout · click "设为当前" on a non-active card · click model chip on active card and pick a different model · open ··· → Test connection / Re-enter key / Delete with confirm

Collapse each provider card to one header row (label, masked key, optional
base URL). The "Active" badge or a compact "set active" button sits on the
right; the model selector is hidden on non-active providers and rendered as
a click-to-edit chip on the active card. Per-row actions (Test connection,
Re-enter key, Delete) move into a ··· overflow menu, and the duplicated
dashed "Add provider" button at the bottom of the list is removed.

Signed-off-by: hqhq1025 <1506751656@qq.com>
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Findings

  • [Major] Unhandled IPC failure in "Test connection" action — window.codesign.connection.testActive() is awaited without try/catch, so bridge/runtime errors become unhandled promise rejections and no user-facing error is shown, violating the no-silent-fallback rule. Evidence apps/desktop/src/renderer/src/components/Settings.tsx:658
    Suggested fix:

    async function handleTestConnection() {
      if (!window.codesign) return;
      try {
        const res = await window.codesign.connection.testActive();
        if (res.ok) {
          pushToast({ variant: 'success', title: t('settings.providers.toast.connectionOk') });
        } else {
          pushToast({
            variant: 'error',
            title: t('settings.providers.toast.connectionFailed'),
            description: res.hint || res.message,
          });
        }
      } catch (err) {
        pushToast({
          variant: 'error',
          title: t('settings.providers.toast.connectionFailed'),
          description: err instanceof Error ? err.message : t('settings.common.unknownError'),
        });
      }
    }
  • [Major] Model chip can display unsaved value after failed save — handleChange updates local state and closes edit mode before persistence completes; save swallows errors and does not roll back, so UI may show a model that was not actually saved. Evidence apps/desktop/src/renderer/src/components/Settings.tsx:776
    Suggested fix:

    async function save(next: string): Promise<boolean> {
      if (!window.codesign) return false;
      try {
        const updated = await window.codesign.settings.setActiveProvider({ provider, modelPrimary: next });
        setConfig(updated);
        return true;
      } catch (err) {
        pushToast({
          variant: 'error',
          title: t('settings.providers.toast.modelSaveFailed'),
          description: err instanceof Error ? err.message : t('settings.common.unknownError'),
        });
        return false;
      }
    }
    
    function handleChange(v: string) {
      const prev = primary;
      setPrimary(v);
      setEditing(false);
      void save(v).then((ok) => {
        if (!ok) setPrimary(prev);
      });
    }

Summary

  • Review mode: initial
  • 2 issues found in changed lines. docs/VISION.md and docs/PRINCIPLES.md were referenced in instructions but are absent in this checkout (Not found in repo/docs).
  • Residual risk: no test updates were included for the new overflow-menu connection flow or failed active-model save rollback behavior.

Testing

  • Not run (automation)

open-codesign Bot


async function handleTestConnection() {
if (!window.codesign) return;
const res = await window.codesign.connection.testActive();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

testActive() is not wrapped in try/catch. If IPC throws (bridge/runtime issue), this becomes an unhandled rejection and no user-facing error is surfaced. Please catch and toast the error path.

}

function handlePrimaryChange(v: string) {
function handleChange(v: string) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

handleChange updates local primary before persistence completes, while save swallows errors. On failure the chip can show an unsaved model. Please return a success flag (or rethrow) from save and roll back primary on failure.

… failure

Codex flagged two Major issues in #116:
- handleTestConnection awaited testActive() without try/catch, leaking
  bridge errors as unhandled promise rejections.
- Model chip optimistically set new value before save completed; on save
  failure the UI showed an unsaved model. Now save() returns boolean and
  handleChange rolls back primary to its previous value when save fails.

Signed-off-by: hqhq1025 <1506751656@qq.com>
@hqhq1025 hqhq1025 deleted the branch wt/unify-api-config April 19, 2026 17:12
@hqhq1025 hqhq1025 closed this Apr 19, 2026
hqhq1025 added a commit that referenced this pull request Apr 19, 2026
… failure

Codex flagged two Major issues in #116:
- handleTestConnection awaited testActive() without try/catch, leaking
  bridge errors as unhandled promise rejections.
- Model chip optimistically set new value before save completed; on save
  failure the UI showed an unsaved model. Now save() returns boolean and
  handleChange rolls back primary to its previous value when save fails.

Signed-off-by: hqhq1025 <1506751656@qq.com>
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Findings

  • None.

Summary

  • Review mode: follow-up after new commits
  • No issues found in added/modified lines of the latest diff.
  • docs/VISION.md and docs/PRINCIPLES.md: Not found in repo/docs.
  • Residual risk: no Vitest/Playwright coverage was added for overflow-menu interactions and active-model edit/rollback behavior.

Testing

  • Not run (automation)

open-codesign Bot

hqhq1025 added a commit that referenced this pull request Apr 20, 2026
…#117)

* feat(desktop): simplify provider cards in Settings → API 服务

Collapse each provider card to one header row (label, masked key, optional
base URL). The "Active" badge or a compact "set active" button sits on the
right; the model selector is hidden on non-active providers and rendered as
a click-to-edit chip on the active card. Per-row actions (Test connection,
Re-enter key, Delete) move into a ··· overflow menu, and the duplicated
dashed "Add provider" button at the bottom of the list is removed.

Signed-off-by: hqhq1025 <1506751656@qq.com>

* fix(desktop): catch test-connection errors and roll back chip on save failure

Codex flagged two Major issues in #116:
- handleTestConnection awaited testActive() without try/catch, leaking
  bridge errors as unhandled promise rejections.
- Model chip optimistically set new value before save completed; on save
  failure the UI showed an unsaved model. Now save() returns boolean and
  handleChange rolls back primary to its previous value when save fails.

Signed-off-by: hqhq1025 <1506751656@qq.com>

* fix(desktop): surface bridge failures + guard model rollback race

Addresses codex review on #117:
- Test-connection + model save paths now toast an error when
  window.codesign is missing instead of silently returning.
- ProviderModelEditor tracks a monotonic save counter so a stale failure
  from an earlier save cannot roll back the UI past a later successful
  selection.

Signed-off-by: hqhq1025 <1506751656@qq.com>

---------

Signed-off-by: hqhq1025 <1506751656@qq.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.

1 participant