backstage / backstage/community-plugins

🚀 Announcements: Per-announcement dismiss tracking for multiple banners

Open
#9,118 7 comments 0 reactions 1 assignee Claimed by @fredericoferreiracosta View on GitHub
enhancement workspace/announcements
Dominant language
TypeScript
Stars
422
Forks
697
Avg merge
2d 6h
Merged PRs (30d)
286

Description

### Workspace

announcements

### 🔖 Feature description

The current banner dismiss mechanism uses a single lastSeenDate timestamp stored in localStorage. This makes it impossible to reliably display and independently dismiss multiple announcement banners. Dismissing any announcement updates the timestamp to that announcement's created_at, which inadvertently hides all older announcements — even if the user never saw them.

The feature request is to replace the single-timestamp approach with per-announcement dismiss tracking (e.g., a Set of dismissed announcement IDs), so that each banner can be dismissed independently without affecting the visibility of others.

### 🎤 Context

When using NewAnnouncementBanner with max > 1, the component fetches multiple announcements and renders a banner for each unseen one. However, the dismiss behavior is broken:

1. User sees 3 unseen banners (announcements A, B, C ordered oldest to newest)
2. User dismisses C (the newest) → markLastSeenDate is set to C's created_at
3. A and B immediately disappear because their created_at < lastSeenDate

Additionally, since lastSeenDate is stored in browser localStorage, the "seen" state is lost entirely in incognito mode, new devices, or when clearing browser data — causing all banners to reappear.

This makes the max prop on NewAnnouncementBanner effectively useless for showing multiple banners with independent dismiss behavior.

### ✌️ Possible Implementation

Replace the single timestamp with a Set of dismissed announcement IDs in WebStorage:

1. AnnouncementsApi interface — Add dismissAnnouncement(id: string): void and isAnnouncementDismissed(id: string): boolean. Deprecate markLastSeenDate / lastSeenDate (keep for backward compat).

2. AnnouncementsClient — Store a dismissed_announcement_ids array in WebStorage. Cap at a reasonable size (e.g., last 50 IDs) to prevent localStorage bloat.

3. NewAnnouncementBanner — Filter by !isAnnouncementDismissed(id) instead of lastSeen < created_at.

4. AnnouncementsCard — Use the same logic for the "new" megaphone icon.

5. Migration — On first load, if user_last_seen_date exists, convert it: mark all announcements with created_at <= lastSeenDate as dismissed, then remove the old key.

### 👀 Have you spent some time to check if this feature request has been raised before?

- [x] I checked and didn't find similar issue

### 🏢 Have you read the Code of Conduct?

- [x] I have read the [Code of Conduct](https://github.com/backstage/community-plugins/blob/main/CODE_OF_CONDUCT.md)

### Are you willing to submit PR?

Yes I am willing to submit a PR!

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.