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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions