feat(desktop): dedicated Providers settings + polished Accounts/API-keys UX (#38551)
* feat(desktop): dedicated Providers settings with Accounts/API-keys subnav Rework provider configuration in the desktop app into its own Providers page that mirrors the first-run onboarding picker, instead of burying provider keys in the generic Tools & Keys list. - Add a Providers settings page (providers-settings.tsx) reusing the onboarding picker cards/ApiKeyForm so the two surfaces stay identical - Add a sidebar subnav (Accounts vs API keys) backed by a deep-linkable `pview` URL param; nested OverlayNavItem variant for a lighter active state so children don't compete with the parent item - Scope provider search to the active sub-view in its native card format (no more accordion fallback); collapse the API-key grid to the top providers behind a "Show all" toggle to cut scrolling - Launch real in-app OAuth from settings via startManualProviderOAuth; fix the misleading red "reason" banner that showed during an active connect (neutral style, hidden during a flow, omitted for direct per-provider launches) - Expand PROVIDER_GROUPS and add longest-prefix matching so providers like xAI/Ollama group correctly instead of landing under "Other" - Drop redundant messaging API keys from Tools & Keys (channel_managed) Co-authored-by: Cursor <cursoragent@cursor.com> * feat(desktop): Cursor-style provider key list with inline inputs Replace the card-grid API-key form on the Providers page with a per-provider list (mirrors Cursor's API keys section): - One row per vendor with its primary key input inline; rows with extra vars (base URL, region, alt tokens) expand to reveal those on focus - Set keys show their redacted value as the placeholder; Save appears on edit, Remove on a set key - Hide redundant alias key fields (e.g. ANTHROPIC_TOKEN vs ANTHROPIC_API_KEY) unless already set, and label set aliases by env var name so they're unambiguous - Smaller mono input text + compact height Co-authored-by: Cursor <cursoragent@cursor.com> * style(desktop): flatten providers settings UI chrome Tighten the providers settings surface to match the newer desktop style: remove extra card rails/borders in API-key rows, reduce visual noise in the providers subnav, replace bespoke link-like controls with shared text-button variants, and improve key input readability. * feat(desktop): rework providers settings UI - Flatten the shared OAuth picker rows (accounts + onboarding): drop the rounded-2xl/border cards for flat hover-bg rows; Nous hero keeps a subtle tint plus an animated blue→purple arc border. - Key fields collapse to a single input: a set key reads read-only (redacted) and edits in place on focus/click — no Replace/Cancel chrome. Save on type, Esc cancels (without closing the overlay), "Remove or esc to cancel" hint. - Non-key overrides render boxless, content-sized (field-sizing) and right-anchored; advanced fields align under the primary key column. - Add `xs` control size; size fields via padding (no fixed heights). - Cards expand on key-input focus; chevron shows on hover/expanded; expanded state uses a ring + softer bg tier so hover ≠ focus. - Relocate "Get a key" to the bottom-right of the expanded panel; drop the redundant provider description. - Cmd+K: add Providers (accounts) and Provider API keys deep-links. * fix(desktop): flatten provider fields, drop input shadows, fix Cmd+K provider rank - KeyField: collapse to one stacked label-above-input form field (drop the bespoke `naked`/inline/column branches); empty advanced overrides fade until hover/focus/set - styles: kill the resting + focus drop shadow on shared input chrome so form inputs sit flat (composer keeps its own shadow) - Cmd+K: drop stray `providers` keyword from Skills & Tools so the Providers settings entry ranks first for "provider" * fix(desktop): nous portal arc blue → orange * fix(desktop): rank appearance above settings in Cmd+K --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Brooklyn Nicholson <brooklyn.bb.nicholson@gmail.com>
This commit is contained in:
co-authored by
Cursor
Brooklyn Nicholson
parent
b36a30db20
commit
9cbc37e25b
@@ -346,20 +346,49 @@ export function requestDesktopOnboarding(reason = DEFAULT_ONBOARDING_REASON) {
|
||||
// onboarding flow (OAuth rows, API-key form, model-confirm) instead of
|
||||
// duplicating provider UI. Sets manual=true so the overlay shows the picker
|
||||
// even though configured===true, and refreshes the provider list.
|
||||
export function startManualOnboarding(reason = 'Add or switch inference provider.') {
|
||||
export function startManualOnboarding(reason: null | string = 'Add or switch inference provider.') {
|
||||
patch({
|
||||
manual: true,
|
||||
requested: true,
|
||||
reason: reason.trim() || DEFAULT_ONBOARDING_REASON,
|
||||
// `null` opts out of the prompt banner entirely (e.g. when the user already
|
||||
// picked a specific provider and we auto-start its sign-in).
|
||||
reason: reason ? reason.trim() || DEFAULT_ONBOARDING_REASON : null,
|
||||
flow: { status: 'idle' }
|
||||
})
|
||||
void refreshProviders()
|
||||
}
|
||||
|
||||
// One-shot hand-off used when the dedicated Providers settings page launches a
|
||||
// specific provider's sign-in: we open the manual onboarding overlay AND
|
||||
// remember which provider to start, so the overlay drives that exact OAuth
|
||||
// flow instead of re-showing the picker the user just clicked through.
|
||||
// Module-level (not store state) because it's consumed immediately on the next
|
||||
// overlay render and never needs to persist or re-render anything itself.
|
||||
let pendingProviderOAuthId: null | string = null
|
||||
|
||||
export function startManualProviderOAuth(providerId: string, reason: null | string = null) {
|
||||
pendingProviderOAuthId = providerId
|
||||
startManualOnboarding(reason)
|
||||
}
|
||||
|
||||
// Read the pending provider id without clearing it. The overlay only clears it
|
||||
// (via clearPendingProviderOAuth) once it has actually launched that provider,
|
||||
// so a transient empty/failed provider fetch doesn't drop the hand-off and the
|
||||
// deep-link can still auto-start after the list loads.
|
||||
export function peekPendingProviderOAuth(): null | string {
|
||||
return pendingProviderOAuthId
|
||||
}
|
||||
|
||||
export function clearPendingProviderOAuth() {
|
||||
pendingProviderOAuthId = null
|
||||
}
|
||||
|
||||
// Dismiss a manually-opened provider selector without touching the existing
|
||||
// (working) configuration. Only valid in the manual path — the unconfigured
|
||||
// first-run flow has no close affordance because the app can't run yet.
|
||||
export function closeManualOnboarding() {
|
||||
pendingProviderOAuthId = null
|
||||
|
||||
patch({ manual: false, requested: false, flow: { status: 'idle' } })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user