Skip to content

Conversation

@ssncferreira
Copy link
Contributor

@ssncferreira ssncferreira commented Nov 24, 2025

Problem

Users may not realize that task notifications are disabled by default. To improve awareness, we show a warning alert on the Tasks page when all task notifications are disabled.

Alert visibility logic:

  • Shows when all task notification templates (Task Working, Task Idle, Task Completed, Task Failed) are disabled
  • Can be dismissed by the user, which stores the dismissal in the user preferences API
  • If the user later enables any task notification in Account Settings, the dismissal state is cleared so the alert will show again if they disable all notifications in the future
Screenshot 2025-11-25 at 17 48 17

Changes

  • Added a warning alert to the Tasks page when all task notifications are disabled
  • Introduced new /users/{user}/preferences endpoint to manage user preferences (stored in user_configs table)
  • Alert is dismissible and stores the dismissal state via the new user preferences API endpoint
  • Enabling any task notification in Account Settings clears the dismissal state via the preferences API
  • Added comprehensive Storybook stories for both TasksPage and NotificationsPage to test all alert visibility states and interactions

Closes: coder/internal#1089

@ssncferreira ssncferreira force-pushed the ssncferreira/feat-site-tasks-notifications-disabled branch 4 times, most recently from 104c727 to 57f4afc Compare November 25, 2025 17:33
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-site-tasks-notifications-disabled branch from 57f4afc to 322c8e9 Compare November 25, 2025 17:44
@ssncferreira ssncferreira marked this pull request as ready for review November 25, 2025 17:57
Copy link
Member

@aslilac aslilac left a comment

Choose a reason for hiding this comment

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

I don't think localStorage is the right way to store the dismissal state here. I think this would be a very good candidate for storing in the user_configs table. You could follow the plumbing for theme_preference for 90% of the implementation, and then the preference would persist across machines and any potential storage clearing a browser or operating system might do.

@ssncferreira
Copy link
Contributor Author

I don't think localStorage is the right way to store the dismissal state here. I think this would be a very good candidate for storing in the user_configs table. You could follow the plumbing for theme_preference for 90% of the implementation, and then the preference would persist across machines and any potential storage clearing a browser or operating system might do.

@aslilac Thank you for the review!
I went with the localStorage approach since it’s the simplest and feels more like a frontend concern. IIUC, your suggestion is to store the dismissal state in the backend (user_configs table), but that feels unnecessary for a one-time dismissible alert. Backend storage would mainly help sync the state across devices/browsers or handle cases where users clear their browser storage, but that still seems like more complexity than this feature warrants, given that most users will most likely only see it once.

Since this is more of a transient “don’t show this again” UI state rather than a real user preference, localStorage feels like an appropriate solution for now. Maybe if users start complaining about this, this is something we can improve in the future. Does that work for you?

@aslilac
Copy link
Member

aslilac commented Nov 25, 2025

that feels unnecessary for a one-time dismissible alert

but that's my point. if we don't persist this state somewhere centrally it's not "one-time". and it is a user preference: a preference to not be notified about this again. your current implementation doesn't store the preference for a specific user, it stores it for a specific browser. if you logged in with a different account it would still be dismissed.

it's not a "front-end" concern, it is a state concern.

mafredri added a commit that referenced this pull request Nov 26, 2025
Add comprehensive documentation for active frontend pattern migrations
discovered through analysis of 200+ git commits touching site/ files:

Core Migrations:
- Emotion → Tailwind CSS (strict 'no new emotion' policy)
- MUI Components → Custom/Radix/shadcn (Tooltips, Tables, Buttons)
- MUI Icons → lucide-react with specific icon mappings
- spyOn → queries parameter for GET endpoint mocks in Storybook
- localStorage → user_configs table for user preferences

New Documentation:
- Icon migration mappings (BusinessIcon→Building2Icon, etc.)
- Radix component prop naming conventions (placement→side)
- cn() utility usage for conditional className merging
- Chromatic testing best practices (prefer snapshots over assertions)

Includes concrete before/after examples and migration patterns to guide
developers away from deprecated approaches toward current best practices.

Analysis based on PRs: #20948, #20946, #20938, #20905, #20900, #20869,
#20849, #20808, #20530, #20479, #20261, #20201, #20200, #20193, #20318

---

🤖 This change was written by Claude Sonnet 4.5 Thinking using mux and reviewed by a human 🏂
@ssncferreira
Copy link
Contributor Author

but that's my point. if we don't persist this state somewhere centrally it's not "one-time". and it is a user preference: a preference to not be notified about this again. your current implementation doesn't store the preference for a specific user, it stores it for a specific browser. if you logged in with a different account it would still be dismissed.

That makes sense 🙂 I was thinking in terms of the user persona I assumed for Coder UI (generally using a single browser, rarely clearing storage, and not sharing that browser with others), so localStorage felt like a reasonable, lightweight option. That’s why I suggested starting simple and moving the preference into user_configs if it later turned out to cause confusion or complaints from users.

But I understand your point about this being a true user preference rather than browser-local state, and how storing it centrally avoids the cross-browser and cross-account inconsistencies you mentioned.

I’ll update the PR to persist the dismissal in user_configs.

@ssncferreira ssncferreira requested a review from aslilac November 26, 2025 22:12
Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

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

Small suggestions for BE but looks good otherwise 👍🏻

Copy link
Contributor

@DanielleMaywood DanielleMaywood left a comment

Choose a reason for hiding this comment

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

I'm happy with what we have. Left a non-blocking nit and left a 👍 emoji on @mafredri's comments that I agree with

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

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

One last (minor) comment on the backend implementation, I'll submit this now and start looking at the FE changes.

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

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

I had some minor comments, but FE looks good to me. 👍🏻

};

export function isTaskNotification(tmpl: NotificationTemplate): boolean {
return tmpl.group === "Task Events";
Copy link
Member

Choose a reason for hiding this comment

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

(Side-note: It would be nice if we had real enums for these.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, we are missing enums in the FE for a lot of things.

updatePreferencesMutation.mutate({
task_notification_alert_dismissed: false,
});
}
Copy link
Member

Choose a reason for hiding this comment

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

Fine for now, but should we consider doing this on the backend? Ideally this change would be propagated even if done directly via API or UI (or CLI if we support that, or will support that in the future).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I also thought about that and that might be a better approach. I will address that in a follow-up PR.

@ssncferreira ssncferreira merged commit f8d9a80 into main Nov 28, 2025
35 checks passed
@ssncferreira ssncferreira deleted the ssncferreira/feat-site-tasks-notifications-disabled branch November 28, 2025 16:51
@github-actions github-actions bot locked and limited conversation to collaborators Nov 28, 2025
@ssncferreira ssncferreira added cherry-pick/v2.29 Needs to be cherry-picked to the 2.29 release branch and removed cherry-pick/v2.29 Needs to be cherry-picked to the 2.29 release branch labels Nov 28, 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.

Indicator of Tasks' notifications being disabled

5 participants