Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Sep 2, 2025

Fixes #7599

Summary

This PR replaces the problematic "Unsaved Changes" dialog with a modern auto-save system that provides a better user experience.

Problem

  • Users were getting stuck with an "Unsaved Changes" dialog when switching profiles
  • The dialog forced users to either cancel (getting stuck) or discard their changes (losing data)
  • This was causing frustration and data loss

Solution

  • Removed the intrusive unsaved changes dialog completely
  • Implemented debounced auto-save (500ms delay) for all provider settings
  • Added visual save status indicator (three dots animation during save)
  • Prevents profile switching while save is in progress
  • Added error handling with toast notifications for save failures

Important

Replaces unsaved changes dialog with an auto-save system in SettingsView.tsx, adding debounced saving, visual indicators, and error handling.

  • Behavior:
    • Replaces unsaved changes dialog with auto-save in SettingsView.tsx.
    • Implements 500ms debounced auto-save for provider settings.
    • Adds visual save status indicator (three dots animation) and error handling with toast notifications.
    • Prevents profile switching during save.
  • Tests:
    • Updates tests in SettingsView.spec.tsx to reflect auto-save behavior.
    • Removes tests related to unsaved changes dialog.
  • Localization:
    • Updates settings.json for new save status messages.

This description was created by Ellipsis for 7587a2f. You can customize this summary. It will automatically update as commits are pushed.

- Remove disruptive "Unsaved Changes" confirmation dialog
- Implement automatic saving with 500ms debouncing
- Add visual status indicators (orange for saving, green for saved, red for errors)
- Prevent profile switching during active save operations
- Update translation strings to reflect new behavior
- Simplify checkUnsaveChanges to work with auto-save
- Background saves continue even when closing settings panel

Fixes #7599
- Remove intrusive unsaved changes dialog that blocked profile switching
- Implement debounced auto-save (500ms delay) for all provider settings
- Add visual save status indicator (three dots animation during save)
- Prevent profile switching while save is in progress
- Add error handling with toast notifications for save failures
- Update tests to reflect new auto-save behavior

Fixes #7599
@roomote roomote bot requested review from cte, jr and mrubens as code owners September 2, 2025 20:24
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Sep 2, 2025
Copy link
Contributor Author

@roomote roomote bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing my own code is like debugging in a mirror - everything looks backwards but the bugs are still mine.

setSaveStatus("saved")
// Reset to idle after showing saved status for a bit
setTimeout(() => {
setSaveStatus("idle")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional? The setTimeout here could accumulate if users make rapid changes, potentially causing a memory leak. Consider storing the timeout reference and clearing it before setting a new one:

Suggested change
setSaveStatus("idle")
const timeoutRef = useRef<NodeJS.Timeout>();
// ...
if (timeoutRef.current) clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => {
setSaveStatus("idle")
}, 2000)

// If we're currently saving, wait for it to complete
if (saveStatus === "saving") {
// Wait a bit for save to complete, then execute
setTimeout(then, 100)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 100ms timeout here seems arbitrary. What happens if the save operation takes longer than 100ms? Could we use a more robust approach like a Promise or event-based system to ensure the action only executes after save completes?

}, 2000)
} catch (error) {
setSaveStatus("error")
setSaveError(error instanceof Error ? error.message : "Failed to save settings")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When saveStatus is 'error', users have no way to retry the save except by making another change. Should we consider adding a manual retry button or automatically retry after a delay?

<div className="flex items-center gap-1">
{saveStatus === "saving" && (
<StandardTooltip content={t("settings:status.saving")}>
<Circle className="w-3 h-3 fill-orange-500 text-orange-500" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These status indicators rely solely on color to convey meaning, which could be problematic for users with color vision deficiencies. Consider adding aria-label attributes or visible text labels for better accessibility:

Suggested change
<Circle className="w-3 h-3 fill-orange-500 text-orange-500" />
<Circle className="w-3 h-3 fill-orange-500 text-orange-500" aria-label="Saving changes" />

// Volume slider should not be visible when sound is disabled
expect(screen.queryByTestId("sound-volume-slider")).not.toBeInTheDocument()
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests cover the happy path well, but we're missing coverage for error scenarios. Could we add tests for:

  • Save failures and error status display
  • Race conditions during rapid changes
  • Profile switching while save is in progress

profileThresholds,
openRouterImageApiKey,
openRouterImageGenerationSelectedModel,
])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dependency array with 70+ items is quite unwieldy. Could we simplify this by either:

  1. Using a single state object to reduce dependencies
  2. Extracting this to a custom hook like useAutoSave
  3. Using a ref for values that don't need to trigger re-execution?

@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Sep 2, 2025
@daniel-lxs daniel-lxs moved this from Triage to PR [Needs Prelim Review] in Roo Code Roadmap Sep 2, 2025
@hannesrudolph hannesrudolph added PR - Needs Preliminary Review and removed Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. labels Sep 2, 2025
@daniel-lxs daniel-lxs closed this Sep 16, 2025
@github-project-automation github-project-automation bot moved this from PR [Needs Prelim Review] to Done in Roo Code Roadmap Sep 16, 2025
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Sep 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working PR - Needs Preliminary Review size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Replace Disruptive "Unsaved Changes" Dialog with a Seamless Auto-Save System

4 participants