Agentic UI: add persistent notifications for updates - #4204
Conversation
📊 Performance Test ResultsComparing f403302 vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
…-update-notification # Conflicts: # apps/studio/src/ipc-handlers.ts # apps/studio/src/preload.ts # apps/studio/src/storage/storage-types.ts # apps/studio/src/storage/user-data.ts # apps/ui/src/components/app-toasts/index.tsx # apps/ui/src/components/sidebar-layout/index.tsx # apps/ui/src/components/sidebar-layout/style.module.css # apps/ui/src/data/app-messages.test.ts # apps/ui/src/data/app-messages.ts # apps/ui/src/data/core/connectors/hosted/index.ts # apps/ui/src/data/core/connectors/ipc/index.ts # apps/ui/src/data/core/connectors/local/index.ts # apps/ui/src/data/core/types.ts # apps/ui/src/data/queries/use-import-site.ts
…ate handlers async
…-update-notification # Conflicts: # apps/ui/src/app/app-providers.tsx
…-update-notification # Conflicts: # apps/ui/src/data/core/index.ts
nightnei
left a comment
There was a problem hiding this comment.
The animation is not smoth, feels like it gets stuck before disappearing
https://github.com/user-attachments/assets/6c10caf4-f730-41c1-b6bb-6a1071a5ffbd
| autoUpdater.on( 'update-downloaded', async ( _event, releaseNotes, releaseName ) => { | ||
| updaterState = 'waiting-for-restart'; | ||
| console.log( 'Update has been downloaded' ); | ||
| downloadedVersion = typeof releaseName === 'string' && releaseName ? releaseName : null; |
There was a problem hiding this comment.
If it's string, then I don't think we need to check for existance:
| downloadedVersion = typeof releaseName === 'string' && releaseName ? releaseName : null; | |
| downloadedVersion = typeof releaseName === 'string' ? releaseName : null; |
There was a problem hiding this comment.
Moreover, we use it just for console.log, then probably tehre is no reason to use extra dewnloadedVersion variable at all. Also, do we need this console.log?
| }, | ||
|
|
||
| onAppUpdateStatusChanged( listener ) { | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
There was a problem hiding this comment.
Propose creating a Linear issue (or addressing it here) to declare it globally, similar to what we have for Studio Classic - https://github.com/Automattic/studio/blob/trunk/apps/studio/src/preload.ts#L252-L258
…nd ipcListener access
…-update-notification # Conflicts: # apps/ui/src/components/sidebar-layout/index.tsx
Related issues
Related to STU-1984
Builds on #4203 (toast notifications), which landed separately.
How AI was used in this PR
The initial implementation is @katinthehatsite's work from the original branch.
The follow-up work — addressing review findings, simplifying the dismissal plumbing, and merging trunk — was done with Claude Code and reviewed before pushing.
Proposed Changes
Adds persistent message cards to the Agentic UI sidebar. Unlike the toasts from #4203, which fade on their own, these stay until the user acts on them or dismisses them — for things the user needs to see even if they looked away.
The first (and currently only) card tells the user when an app update has been downloaded and is ready to install:
The card layer is deliberately generic (a list of messages filtered by dismissed ids), so future messages — onboarding checklists, announcements — can plug into it. If one of those ever needs a dismissal that outlives a restart, that's the point to add persisted storage for it.
Testing Instructions
The update card only appears when the auto-updater has actually downloaded an update, so fake it locally:
ENABLE_AGENTIC_UI=true npm startsetupUpdates()inapps/studio/src/updates.ts, add:99.9.10card appears, confirming both the live IPC push and that dismissals are version-scoped.Pre-merge Checklist