feat(desktop): full-page Settings + fix API switching pipeline#28
feat(desktop): full-page Settings + fix API switching pipeline#28
Conversation
09be189 to
3658ef9
Compare
There was a problem hiding this comment.
Findings
- [Major] Escape key closes the entire Settings page when Command Palette is open, instead of dismissing the palette first. This changes expected modal/overlay priority and can cause accidental navigation loss while issuing commands. Evidence
apps/desktop/src/renderer/src/App.tsx:70.
Suggested fix:{ combo: 'escape', handler: () => { if (commandPaletteOpen) closeCommandPalette(); else if (view === 'settings') setView('workspace'); }, preventDefault: false, }
Summary
- Review mode: initial
- One major regression found in Escape handling priority.
- Required context docs
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation)
open-codesign Bot
| combo: 'escape', | ||
| handler: () => { | ||
| if (settingsOpen) closeSettings(); | ||
| if (view === 'settings') setView('workspace'); |
There was a problem hiding this comment.
Escape currently checks view === 'settings' before commandPaletteOpen, so when palette is open on Settings it exits the page instead of only dismissing the palette.
if (commandPaletteOpen) closeCommandPalette();
else if (view === 'settings') setView('workspace');There was a problem hiding this comment.
Findings
- [Minor] Locale persistence now has a silent fallback when the bridge is missing, so a broken preload can make the UI switch language without actually saving it. That hides the failure instead of surfacing it, which conflicts with the repo's no-silent-fallback rule. Evidence apps/desktop/src/renderer/src/components/Settings.tsx:777 and apps/desktop/src/renderer/src/components/Settings.tsx:802.
Suggested fix:export async function applyLocaleChange( locale: string, localeApi: { set: (locale: string) => Promise<string> }, ): Promise<string> { const persisted = await localeApi.set(locale); return applyLocale(persisted); } async function handleLocaleChange(v: string) { try { if (!window.codesign?.locale) throw new Error('Locale bridge unavailable'); const applied = await applyLocaleChange(v, window.codesign.locale); setLocale(applied); } catch (err) { ... } }
Summary
- Review mode: follow-up after new commits
- Required context docs
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs. - One minor issue found; no other high-confidence regressions in the touched renderer flow.
Testing
- Not run (automation)
- Vitest coverage was added for the store/settings helpers, but I did not find Playwright coverage for the renderer-level settings navigation or locale switch.
open-codesign Bot
| locale: string, | ||
| localeApi: { set: (locale: string) => Promise<string> } | undefined, | ||
| ): Promise<string> { | ||
| const persisted = localeApi ? await localeApi.set(locale) : locale; |
There was a problem hiding this comment.
This fallback makes the helper look successful even if the locale bridge is missing, which means the UI can switch language without persistence and with no surfaced error. That conflicts with the repo's no-silent-fallback rule.
There was a problem hiding this comment.
Findings
- [Minor] Newly introduced Settings strings bypass i18n, so non-English users can still see English text and the new locale error keys added in this PR remain unused. Evidence:
apps/desktop/src/renderer/src/components/Settings.tsx:810,apps/desktop/src/renderer/src/components/Settings.tsx:1132,packages/i18n/src/locales/en.json:191,packages/i18n/src/locales/zh-CN.json:191.
Suggested fix:const t = useT(); pushToast({ variant: 'error', title: t('errors.localePersistFailed'), description: t('errors.rendererDisconnected'), }); <button aria-label={t('navigation.backToWorkspace')}> {t('navigation.workspace')} </button>
Summary
- Review mode: follow-up after new commits
- 1 minor issue found in changed lines.
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs in this checkout.
Testing
- Not run (automation).
open-codesign Bot
| pushToast({ | ||
| variant: 'error', | ||
| title: 'Failed to save language preference', | ||
| description: 'Renderer is not connected to the main process.', |
There was a problem hiding this comment.
This newly introduced toast title is hardcoded English while this PR also adds locale keys (errors.localePersistFailed) in both locale files. Please use useT() here (and for the new Workspace back label) so language switching is consistent.
6829276 to
0d232fe
Compare
There was a problem hiding this comment.
Findings
- [Minor] Full-page Settings header introduces hardcoded English text, so locale switching remains partially untranslated in this new flow. Evidence:
apps/desktop/src/renderer/src/components/Settings.tsx:1140,apps/desktop/src/renderer/src/components/Settings.tsx:1143.
Suggested fix:const t = useT(); <button aria-label={t('settings.backToWorkspace')}> <ArrowLeft className="w-4 h-4" /> {t('settings.workspace')} </button>
Summary
- Review mode: follow-up after new commits
- 1 minor issue found in changed lines.
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation).
open-codesign Bot
| aria-label="Back to workspace" | ||
| > | ||
| <ArrowLeft className="w-4 h-4" /> | ||
| Workspace |
There was a problem hiding this comment.
[Minor] Hardcoded in the newly added full-page Settings header bypasses i18n and leaves this flow partially untranslated after language switch. Please read from locale keys instead.
Suggested fix:
0d232fe to
fcab129
Compare
There was a problem hiding this comment.
Findings
- No high-confidence issues found in added/modified lines.
Summary
- Review mode: follow-up after new commits
- No issues found in the latest diff.
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.- Residual risk: UI-level regressions in full-page settings flow are only partially covered by unit tests (no E2E signal in this run).
Testing
- Not run (automation)
open-codesign Bot
Part A — Settings full-page view:
- store: replace settingsOpen/openSettings/closeSettings with view enum
(AppView = 'workspace' | 'settings') and setView(v) action
- App.tsx: switch main area based on view instead of rendering a modal overlay
- Settings.tsx: remove modal shell, add ← Workspace back button; keep
AddProviderModal as a local dialog (not a page-level route)
- TopBar.tsx: gear button calls setView('settings')
- CommandPalette.tsx: Open Settings action calls setView('settings')
- ESC keybinding: view==='settings' → setView('workspace')
Part B — API switching pipeline audit + fix:
- ActiveModelSelector: add useEffect to sync local primary/fast state
when config prop changes, preventing stale models after provider switch
- The main pipeline (getApiKeyForProvider, getBaseUrlForProvider,
cachedConfig updates) audited and confirmed correct end-to-end
Tests (+6 new):
- store: setView switches view and closes command palette
- store: setView workspace/settings round-trip
- store: sendPrompt uses updated provider after completeOnboarding
- onboarding-ipc: getApiKeyForProvider returns decrypted key when secret exists
- onboarding-ipc: getApiKeyForProvider throws on missing provider secret
Signed-off-by: hqhq1025 <[email protected]>
When Settings is open and the command palette is also open, pressing ESC now closes the palette without navigating back to workspace. The escape handler in App.tsx previously checked `view === 'settings'` first; flip the priority so `commandPaletteOpen` is evaluated first. Three new store-level tests cover: palette consumed (view stays), plain settings-back, and no-op on workspace. Signed-off-by: hqhq1025 <[email protected]>
Replace the silent fallback in applyLocaleChange / handleLocaleChange with an error toast when window.codesign.locale is absent, so users know the language preference was not saved rather than silently losing it on restart. Signed-off-by: hqhq1025 <[email protected]>
Wire the previously-introduced errors.localePersistFailed and errors.rendererDisconnected locale keys into AppearanceTab's handleLocaleChange toasts (was hardcoded English). Addresses Codex review note that the new locale error keys remained unused. Signed-off-by: hqhq1025 <[email protected]>
…iome errors
- Wire useT through every Settings.tsx subcomponent (AddProviderModal,
ProviderCard, ActiveModelSelector, all four tabs, shell). Replaces
every user-facing English literal with a t() call.
- Add settings.{shell,common,providers,appearance,storage,advanced}
namespaces to en.json + native zh-CN.json (~90 keys per locale).
- Replace non-null assertions in store.ts and store.generationStage.test.ts
with explicit null guards so pre-push lint stays clean without --no-verify.
- Add useT to the Settings.test.ts mock so Vitest can import the module.
Signed-off-by: hqhq1025 <[email protected]>
fcab129 to
17780be
Compare
There was a problem hiding this comment.
Findings
- No high-confidence issues found in added/modified lines.
Summary
- Review mode: follow-up after new commits
- No issues found in the latest diff.
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.- Residual risk: full-page Settings flow still lacks Playwright/E2E coverage for keyboard navigation and view transitions (
Mod+,,Esc, command palette open-settings action).
Testing
- Not run (automation)
open-codesign Bot
Summary
Changes
Part A — Settings as full-page view
Part B — API switching pipeline fix
Part C — Settings Appearance language switch fix
Root cause: `AppearanceTab.handleLocaleChange` called only `window.codesign.locale.set()` (writes to disk) but never called `i18next.changeLanguage()`, so React components did not re-render after language selection.
Fix: Extract `applyLocaleChange(locale, localeApi)` helper that does both:
This matches exactly what `LanguageToggle.tsx` does (both paths are now consistent).
Button / IPC chain audit (Task D)
Summary: 3 broken entries found and fixed in this PR (entries 8, 10, 18/22). No TODO-for-later items; all regressions are addressed here.
Test plan
New tests added
Manual verification steps
Compatibility ✅ | Upgradeability ✅ | No bloat ✅ | Elegance ✅