Notification inbox
Status: ✅ Implemented
Intent
Section titled “Intent”Toasts vanish; work does not. “Your export finished”, “an approval is waiting”, “the import had 3 errors” must survive the moment they happened and be findable later — with an unread count nudging the user. This is the inbox (events with read state), distinct from push toasts (transient) and task queues (work items).
Solution
Section titled “Solution”Implement NotificationsSupplier on the @UI app class:
@UI("")public class BackofficeApp implements NotificationsSupplier {
@Autowired NotificationStore notificationStore; // your inbox
@Override public List<AppNotification> notifications(HttpRequest httpRequest) { // per-user inbox: the user the host framework authenticated (the same identity // @EyesOnly authorization uses) var user = httpRequest.getUserPrincipal().getName(); return notificationStore.latest(user).stream() .map(n -> new AppNotification(n.id(), n.title(), n.text(), n.route(), n.unread(), n.relativeTime())) .toList(); }
@Override public void markNotificationsRead(List<String> ids, HttpRequest httpRequest) { notificationStore.markRead(httpRequest.getUserPrincipal().getName(), ids); }}- The shell shows a bell on the header (next to the theme toggle) with the unread count.
- The bell’s panel lists the entries — title, optional text, display time (
whenis already formatted by the server: it owns locale and relative-time rules). Clicking an entry with aroutenavigates there and marks it read; Mark all read clears the count. - The list is fetched per request through the app-level
_notifications-listaction (the same rail as the@AppContextpickers’ remote search), so it can be per-user and always current;_notifications-read(ids, or"all") marks read and answers the refreshed list. - Pair with long-running jobs: when a background task completes, append an inbox entry so the outcome survives the toast.
In YAML
Section titled “In YAML”A data-authored shell feeds the bell from REST sources instead of a NotificationsSupplier class:
notifications: {source: …, markRead: …} on its type: AppShell — fetched by the browser (or
through the server when the source is proxy: true). See
App shell as data › Header extras.
AppDto.notificationsEnabled turns the bell on; the actions answer
Data{_notifications: [{id, title, text, route, unread, when}]} — same contract from the Java,
.NET and Python servers.
Where it works
Section titled “Where it works”Every renderer. On Redwood the bell sits in the global header (badge with the unread count) and
opens an oj-popup holding JET’s oj-list-view; activating an entry marks it read and navigates to
its route. Demo: demo-vb-pms (PmsHome implements NotificationsSupplier). A data-authored
shell’s notifications.source works there too: the same bell lists it (a proxied source through
_appsource), and opening an entry or Mark all read calls markRead.
Related
Section titled “Related”- Push notifications — the transient sibling
- Task queue — when entries are work items with owners and states