Skip to content

Comments

fix: replace intrusive update modal with toast and fix double-restart bug#841

Merged
charlesvien merged 2 commits intomainfrom
fix/update-notification-ux
Feb 7, 2026
Merged

fix: replace intrusive update modal with toast and fix double-restart bug#841
charlesvien merged 2 commits intomainfrom
fix/update-notification-ux

Conversation

@k11kirky
Copy link
Contributor

@k11kirky k11kirky commented Feb 7, 2026

Problem

  1. Update-available dialog is a large modal that takes up half the screen and interrupts workflow
  2. Users need to press "Restart" twice - first press doesn't actually quit and install the update

Root Cause of Double-Restart Bug

The installUpdate() method called shutdown() which tore down the DI container before quitAndInstall() triggered the before-quit event. When the before-quit handler tried to access the container, it threw an error, preventing a clean quit. On a second press, shutdown() sees _isShuttingDown=true and calls forceExit(), killing the process without the updater installing.

Changes

1. Fix double-restart bug

  • Added cleanupForUpdate() method to AppLifecycleService that does essential cleanup (killing processes, shutting down watchers) without tearing down the DI container
  • Updated UpdatesService.installUpdate() to:
    1. Set isQuittingForUpdate flag FIRST
    2. Call cleanupForUpdate() instead of shutdown()
    3. Then call quitAndInstall()

This ensures the container stays intact for the before-quit handler while still properly cleaning up processes and watchers.

2. Replace update modal with persistent toast

  • Rewrote UpdatePrompt.tsx to show a persistent toast (duration: Infinity) in the bottom right when an update is ready
  • Includes inline "Restart now" and "Later" action buttons directly in the toast
  • Uses stable toast ID for proper dismissal
  • Kept "Check for Updates" dialog unchanged (only shown on manual menu action)

3. Update tests

  • Added cleanupForUpdate mock to lifecycle service tests
  • Verified correct call order: setQuittingForUpdate()cleanupForUpdate()quitAndInstall()
  • Ensured shutdown() is NOT called during update installation

Testing

Automated

  • ✅ All 245 tests pass
  • ✅ Typecheck passes

Manual Testing (Production Build Required)

Updates are only enabled in packaged/production builds, so manual testing requires:

  1. Test the toast notification:

    • Build and package the app
    • Trigger an update check when a new version is available
    • Verify the toast appears in the bottom right (not a large modal)
    • Verify it persists until action is taken
  2. Test single-restart:

    • When update is ready, click "Restart now"
    • Verify the app quits and installs the update on the FIRST click (not requiring a second press)
    • Verify the app restarts with the new version
  3. Test "Later" action:

    • Click "Later" button
    • Verify the toast dismisses
    • Verify you can continue working

Files Modified

  • apps/twig/src/main/services/app-lifecycle/service.ts - added cleanupForUpdate() method
  • apps/twig/src/main/services/updates/service.ts - fixed install flow
  • apps/twig/src/main/services/updates/service.test.ts - updated tests
  • apps/twig/src/renderer/components/UpdatePrompt.tsx - replaced modal with toast

Replace the modal dialog for manual update checks with toast notifications to
match the automatic update notification UX. Now all update notifications use
the same toast pattern:

- Checking: persistent toast with spinner
- Up to date: 3s auto-dismiss toast
- Error: 4s auto-dismiss toast
- Update ready: persistent toast with action buttons (already done)

This provides a consistent, non-intrusive experience whether updates are found
automatically or via manual check from the menu.
@k11kirky
Copy link
Contributor Author

k11kirky commented Feb 7, 2026

closes #814

@charlesvien charlesvien merged commit dbe6308 into main Feb 7, 2026
12 checks passed
@charlesvien charlesvien deleted the fix/update-notification-ux branch February 7, 2026 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants