Originally created by: Akarsh-Hegde
Two things the Settings -> Intelligence panel was getting wrong: it read as pale and greyed out, and switching the AI provider applied on a single click with no confirmation.
The provider cards had their surface layering inverted. The card was painted with --t-box - on the ink palette that is rgba(255,255,255,.055), all but invisible against the desk - behind a 0.5px border at 10% white, while the elements inside it used the solid --t-card.
Swapped to the correct order: card on --t-card, inner elements (glyph, Test button) on --t-box, with a full-weight 1px --t-ctrl-border, badges up from 8.5px to 9.5px, and the dim --t-faint body notes lifted to --t-muted.
Deliberately avoided --t-ctrl for inner fills: it is #FFFFFF on the light palettes, identical to the --t-card those elements now sit on, so they would have disappeared. Everything stays token-based, so it holds across lilac / blush / ink.
A pick stages into local pending state and is written only by an explicit Save - matching every other Settings section (Advanced, Capture and Notifications all use <SaveButton>). Intelligence was the outlier.
(provider, custom_id) pair, so switching between two custom endpoints registers as a change.The old code applied the pick optimistically via patch() before saving, with a comment claiming save "rolls the store back on failure". It does not - useRuntimeSettings.save only calls setSettings on success (it swallows the error), so a failed write left the panel claiming a provider the daemon had rejected. With nothing written until Save there is nothing to roll back, and a failed save now keeps the staged pick so the user can retry without re-picking.
auto-fill / minmax(232px, 1fr), giving Settings a third column while the narrower setup wizard naturally keeps two.AddCustomProvider, since only it knows whether the form is open.Also fixes a missing space in "<name> isn't in use yet" and drops a dead missing local.
npm run build (UI) passesbun test - 235 pass, 0 failLlmProviderPicker is shared between this panel and the setup wizard's Intelligence step, so the restyle intentionally lands on both. The Save gating does not - it lives in IntelligenceSection only, because the wizard's own Next/Back is its commit and each pick there writes through by design.IntelligenceSection no longer takes patch; the prop was dropped at the SettingsModal call site. The other three sections still use it, so useRuntimeSettings is unchanged.--t-panel background as content scrolls under it. If the cards feel too narrow at three columns, the 232px minimum in the grid is the single number to raise.๐ค Generated with Claude Code
Originally posted by: coderabbitai[bot]
โจ Finishing Touches
๐งช Generate unit tests (beta)
- [ ] Create PR with unit tests - [ ] Commit unit tests in branch `fix/intelligence-settings-ui`Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
โค๏ธ Share
- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai) - [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai) - [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai) - [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)Comment
@coderabbitai helpto get the list of available commands.Originally posted by: adityaharishch
Review
Overview: Two independent fixes bundled together: (1) the Intelligence provider picker's surface layering was inverted (card painted with the near-invisible
--t-boxtoken while inner elements used the solid--t-card), and (2) switching the AI provider applied on a single click instead of being gated behind Save like every other Settings section. Also widens the section (640px โ 880px) for a third grid column and fixes a real bug found along the way.Correctness
patch()optimistically beforesave(), with a comment claimingsave"rolls the store back on failure." Looking at the describeduseRuntimeSettings.savebehavior (only callssetSettingson success, swallows errors), that comment was simply wrong โ a failed write left the UI claiming a provider the daemon had rejected. Staging the pick in localpendingstate and only committing on an explicit, successful Save is the correct fix, and it now keeps the staged pick on failure so retry doesn't require re-picking.(provider, custom_id)as a pair (not justprovider) is correct โ otherwise switching between two custom endpoints wouldn't register as a change.onChange'sbackToSavedlogic correctly clears the stage when the user re-picks whatever is already saved, so Save never offers a no-op write.IntelligenceSectionsignature change (droppingpatch) has exactly one call site (SettingsModal.tsx), updated correctly; the other three sections are untouched.Style / conventions
--t-ctrlvs--t-boxcollapsing to the same value on light palettes), which is good practice for a change that's reasoned-not-rendered per the author's own caveat.Risks / things to verify
--t-panelbackground as content scrolls under it were called out specifically). Recommend an actual visual pass in a running build before merging, particularly the sticky-bar + scroll interaction, before treating this as done.IntelligenceSectionin favor of<SaveButton>'s own status display โ this is consistent with how Advanced/Capture/Notifications already work, but worth a quick check thatSaveButton's error state reads as clearly as the removed custom copy did.onChange/onSave) despite this being a genuine bug fix (previously-silent broken rollback). Givenbun testpassed at 235/0, existing coverage evidently didn't catch the original bug either โ a small test asserting "failed save keeps the pending pick" would directly guard the regression this PR fixes.Verdict: Solid fix for a real, previously-silent bug, with the right architecture (stage โ explicit Save, matching sibling sections). Hold on merging until the "not visually verified" caveat is closed out with an actual look in a running build.
Originally posted by: Akarsh-Hegde
Thanks for the review. Two of the three items are addressed in
203c2df4; the third is genuinely yours to close, and I've kept it open rather than papering over it.Addressed
Test coverage for the staged-pending logic - added
ui/__tests__/intelligence-provider-save.test.ts(16 cases). Followed the house idiom for a repo with no React render harness (plan-store/oauth-setup-lifecycle): model the transitions, then scan the source for the shape that keeps them true. It pins your explicit ask - a failed save keeps the staged pick - plus the(provider, custom_id)pair comparison and the clear-on-'saved'-only rule.Two cases are deliberate counter-examples so the guards can't be vacuous:
patch()path and asserts it retains a provider the daemon rejected (the bug this PR fixes),The source scans run against a comment-stripped copy - the module header describes the removed
patch()-on-click behaviour, so scanning raw text would conflate documenting the old bug with still doing it. (That assertion genuinely fired on the first run, which is a decent sign the scan isn't inert.)Suite is now 251 pass / 0 fail.
SaveButtonerror copy - you were right that "Failed to save" drops something the removed line carried. I left<SaveButton>alone, since it's shared with Advanced/Capture/Notifications and changing it would ripple into all three. Instead the line directly above it now adapts on failure:That carries the two things generic status can't: which provider failed, and that the pick survived - which is the whole point of keeping the stage on error.
Not addressed - needs a running build (this is the merge blocker)
The visual pass is still open, and I can't close it. I have no way to see the rendered webview. I considered a standalone token-accurate preview page, but rejected it: it would show colour magnitude on static markup and not the thing you specifically named - the sticky
--t-panelbar as real content scrolls under it inside the real modal. Shipping that as "visually verified" would claim a gate was closed when it wasn't.So this needs about two minutes from someone with the app running:
Then Settings โ Intelligence, and click a provider you're not currently on (the sticky Save bar only appears while a pick is staged). Worth checking in each of
lilac/blush/ink(Settings โ Appearance):--t-panelbackground as cards scroll beneath it. The named risk.232pxminimum in the picker'sauto-fillgrid is the single number to raise.Verdict: agreed, not ready to merge until [#1] is looked at. Everything else is closed.
Related
Tickets:
#1Ticket changed by: Akarsh-Hegde