Skip to content

[UX] Add save indicator for per-view API configuration changes #917

Description

@easonLiangWorldedtech

[UX] Add save indicator for per-view API configuration changes

Problem

When a user modifies their API profile settings in SettingsView, there's no visual indication that these changes are stored in view-local state (not global state). If the user switches tabs without explicitly saving, their view-local changes may be lost on extension reload or overwritten by another tab's changes.

Evidence

Code locations:

  • SettingsView.tsx:136: const [isChangeDetected, setChangeDetected] = useState(false) — tracks SettingsView panel changes, but NOT view-local persistence state
  • ClineProvider.ts:499-515: saveViewState() persists to view-specific keys (__view_state_{id}_mode, etc.)
  • SettingsView.tsx:452: vscode.postMessage({ type: "upsertApiConfiguration", ... }) — writes to global state, not view-local

Reproduction:

1. Tab A (sidebar): User opens SettingsView → changes API key for OpenRouter profile
2. isChangeDetected = true (SettingsView tracks this)
3. User clicks "Save" → upsertApiConfiguration message sent → global state updated
4. BUT: viewLocalState.apiConfiguration may NOT be synced yet (depends on timing)
5. If user switches to Tab B before sync completes, Tab A's changes are still in view-local buffer
6. On extension reload, if view-specific keys aren't persisted, Tab A loses its API config

Root Cause

SettingsView.isChangeDetected tracks panel-level changes (fields modified within the SettingsView UI), but doesn't track whether those changes have been:

  1. Persisted to view-local state (saveViewState())
  2. Synced to global state (syncViewStateToGlobal())

There's no "unsaved" indicator that tells users their API config changes are only stored in session-scoped view-local state.

Proposed Fix

Option A: Unsaved badge in SettingsView header (recommended)

// In SettingsView.tsx, add to header area:
{isChangeDetected && !viewLocalStateSynced && (
    <Tooltip content="API configuration changes are stored per-tab and will be lost on extension reload">
        <Badge variant="warning" size="sm">Unsaved</Badge>
    </Tooltip>
)}

// Add state tracking:
const [viewLocalStateSynced, setViewLocalStateSynced] = useState(true)

useEffect(() => {
    if (isChangeDetected) {
        setViewLocalStateSynced(false)
    } else {
        // Sync to view-local state after save completes
        setViewLocalStateSynced(true)
    }
}, [isChangeDetected])

Option B: Save/discard dialog on tab switch (future enhancement)

  • When user switches tabs with unsaved view-local changes, show a confirmation dialog:
    "You have unsaved API configuration changes in this tab. Save before switching?"
    [Save] [Discard] [Cancel]
    

Option C: Visual distinction for view-local vs global state

  • Add a subtle indicator (e.g., dot icon) next to the API profile selector when viewLocalState.apiConfiguration !== global apiConfiguration
  • Tooltip: "This tab uses a custom API configuration"

Scope

  • Impact: SettingsView users in parallel mode — especially those who modify API keys/profiles per-tab
  • Risk: Low — adding UI indicators doesn't change behavior, just improves awareness
  • Priority: Medium (prevents data loss confusion)

Design Considerations

  1. Badge placement: Top-right of SettingsView header or next to the "Save" button
  2. Tooltip text: Clear explanation that changes are per-tab and session-scoped
  3. Color coding: Yellow/warning for unsaved, green/checkmark for synced
  4. Auto-sync option: Consider auto-saving view-local state on upsertApiConfiguration message to reduce confusion

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions