Skip to content

feat: add notifications widget in the navbar #16983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 18, 2025

Conversation

BrunoQuaresma
Copy link
Collaborator

@BrunoQuaresma BrunoQuaresma commented Mar 18, 2025

Preview:
Screenshot 2025-03-18 at 10 38 25

Figma file

This PR adds:

  • Notification widget in the navbar
  • Show notifications
  • Option to mark each notification as read
  • Update notifications in realtime

What is next?

  • Option to mark all the notifications as read at once
  • Option to load previous notifications - Right now, it only shows the latest 25 notifications
  • Having custom icons for each type of notification

And about tests?
The notification widget components are well covered by the current stories, but we definitely want to have e2e tests for it. However, in my recent projects, I found more useful to ship the UI features first, get feedback, change whatever needs to be changed, and then, add the e2e tests to avoid major rework.

Related to coder/internal#336

FMT
…ations-widget
@BrunoQuaresma BrunoQuaresma requested review from a team and bcpeinhardt and removed request for a team March 18, 2025 13:41
Copy link
Member

@Parkreiner Parkreiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good to me overall! Just had a few comments/questions

Comment on lines 142 to 143
const res = JSON.parse(event.data) as TypesGen.GetInboxNotificationResponse;
onNewNotification(res);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OneWayWebSocket class handles this, but in the meantime, do we want to add error handling if JSON.parse ever throws an error?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I think it is always good to handle errors. In this case, I think we can just log a warn. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just making a note for myself: this looks like a good candidate for swapping in the OneWayWebSocket class once that PR is merged in

Comment on lines 72 to 74
markAllAsRead={(): Promise<void> => {
throw new Error("Function not implemented.");
}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be on the extra safe side, the return type can be changed to never to indicate that it will always throw an error. Luckily all promise values are assignable to never, too, so you don't even need Promise<never>


type InboxPopoverProps = {
notifications: Notification[] | undefined;
notifications: readonly InboxNotification[] | undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate the readonly update!

useEffect(() => {
const socket = watchInboxNotifications(
(res) => {
safeUpdateNotificationsCache((prev) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaScript rules will ensure that this works, but just to help make sure the code stays readable, could safeUpdateNotificationsCache be moved above the effect?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I'm really surprised that Biome didn't flag this as a missing effect dependency. I would expect that we would need to wrap the callback in useEffectEvent, too

@@ -59,15 +78,15 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({

const markNotificationAsReadMutation = useMutation({
mutationFn: markNotificationAsRead,
onSuccess: (_, notificationId) => {
onSuccess: (res) => {
safeUpdateNotificationsCache((prev) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note, here, too. When I read the code top to bottom, I find it slightly harder to follow the logic when we reference values that haven't been explicitly declared yet

@BrunoQuaresma BrunoQuaresma merged commit ab8ba96 into main Mar 18, 2025
35 checks passed
@BrunoQuaresma BrunoQuaresma deleted the bq/notifications-widget branch March 18, 2025 18:21
@github-actions github-actions bot locked and limited conversation to collaborators Mar 18, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants