Files
plane/apps/web/core/components/common
8f8ce85d80 feat(web): show 'New version available' banner via service worker (#6119)
* feat(web): show 'New version available' banner via service worker

- Update sw.js to wait for SKIP_WAITING message instead of auto-activating
- Add useServiceWorker hook to register SW and detect waiting updates
- Add UpdateBanner component rendered at the top of the app
- On click, sends SKIP_WAITING to the new worker and reloads on controllerchange

* fix(web): address PR review feedback on service worker hook

- Use event.waitUntil(self.skipWaiting()) in sw.js for reliable activation
- Guard setWaitingWorker with navigator.serviceWorker.controller check to skip first install
- Store updatefound handler in a variable for proper cleanup on unmount
- Register controllerchange listener with { once: true } before postMessage

* feat(web): stamp sw.js with build version so browser detects new deployments

- Add version placeholder comment in public/sw.js
- Add swVersionPlugin to vite.config.ts that replaces the placeholder
  with VITE_APP_VERSION (or timestamp) during production builds
- Mark @chevrotain/regexp-to-ast as external to fix langium build error

* fix: remove stale vite workarounds and fix statechange listener leak

- Remove @chevrotain/regexp-to-ast rollup external and langium
  optimizeDeps exclude from vite.config.ts (fixed upstream)
- Fix statechange listener leak in use-service-worker.ts by tracking
  installingWorker and cleaning up before re-attach and on teardown

* fix: use closeBundle hook for sw.js stamping and add aria attrs to update banner

- Switch swVersionPlugin from writeBundle to closeBundle so it runs
  after public assets are copied, resolving outDir via configResolved
- Add role=alert and aria-live=assertive to UpdateBanner for screen
  reader announcements

* fix: attach updatefound listener unconditionally

Always attach updatefound listener after registration so later updates
during the same page session are detected even when reg.installing is
already present at registration time.

* fix(web): address service worker review feedback

- Register controllerchange listener in effect so all tabs reload on update
- Guard with hadController to skip first-time SW installation
- Add cancelled flag to prevent state updates after unmount
- Use regex for sw-version marker and assert it exists in swVersionPlugin

* fix(web): track hasBeenControlled for same-session SW updates

On first-ever visit hadController was always false, so a same-session
update would not trigger a reload. Now we flip hasBeenControlled to true
after the initial controllerchange so subsequent updates reload correctly.

* fix(web): only auto-reload the tab that initiated the SW update

* chore(web): strip service worker down to update-banner-only

Remove workbox caching (NetworkFirst, NetworkOnly routes) from sw.js
and delete both workbox runtime files. The service worker now only
handles SKIP_WAITING and clients.claim() for the app update banner.

Amp-Thread-ID: https://ampcode.com/threads/T-019d4b84-83d7-7455-b971-e5639998ef4f
Co-authored-by: Amp <[email protected]>

* feat: enhance banner component with accent variant and update styling

---------

Co-authored-by: Amp <[email protected]>
Co-authored-by: Prateek Shourya <[email protected]>
2026-04-02 15:04:22 +05:30
..