Skip to content

feat: allow users to get notified about changes in a collective#2541

Open
mejo- wants to merge 3 commits into
mainfrom
feat/subscribe
Open

feat: allow users to get notified about changes in a collective#2541
mejo- wants to merge 3 commits into
mainfrom
feat/subscribe

Conversation

@mejo-

@mejo- mejo- commented May 27, 2026

Copy link
Copy Markdown
Member

Sends notifications if pages got updated or deleted. Doesn't send notifications when a page got created on purpose as usually pages get renamed straight after they got created.

Also allows to turn notifications off completely for a collective, which also silences notifications on being mentioned in a page.

Fixes: #317

🖼️ Screenshots

Collectives Action Menu 1 Collectives Action Menu 2
image image
Notification
image

🚧 TODO

So far it only sends notifications on page updates (content updated, page renamed/moved/deleted, emoji changed). I wonder whether adding/removing members shall trigger a notification as well. And how about tagging/untagging pages etc.?

Also, so far there's only three states: "all changes", "@-mention only" (the default) and "off" (no notifications at all). I wonder whether we want to make this more fine-grained, but maybe that's something for a follow-up later on.

  • Decide if collective actions is the right place for the subscribe toggle in UI
  • Playwright tests
  • Consider activity app integration

🏁 Checklist

  • Code is properly formatted (npm run lint / npm run stylelint / composer run cs:check)
  • Sign-off message is added to all commits
  • Tests (unit, integration and/or end-to-end) passing and the changes are covered with tests

🤖 AI (if applicable)

  • The content of this PR was partly generated using AI tools
  • The AI-generated content was reviewed, comprehended and tested by my

@mejo- mejo- self-assigned this May 27, 2026
@mejo- mejo- added enhancement New feature or request 2. developing labels May 27, 2026
@github-project-automation github-project-automation Bot moved this to 🧭 Planning evaluation (don't pick) in 📝 Productivity team May 27, 2026
@mejo- mejo- moved this from 🧭 Planning evaluation (don't pick) to 🏗️ In progress in 📝 Productivity team May 27, 2026
@mejo-
mejo- force-pushed the feat/subscribe branch 2 times, most recently from 2e07f05 to aa099f0 Compare May 28, 2026 20:54

@marcoambrosini marcoambrosini left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hi Jonas, I think that the location you've chosen makes sense, I would maybe do it like in Talk though, using a sub-action-menu, so we have more space to be clear with labels and icons.

Screen.Recording.2026-05-29.at.16.51.45.mov

On top of that, this could be indeed put in the collective settings dialog. Just like in Talk, the dialog could be exposed to all users, and have the conditional display logic (owner/user) on settings section instead. Templates could also go in here.

@mejo- mejo- changed the title feat: allow users to subscribe to changes in a collective feat: allow users to get notified about changes in a collective Jun 1, 2026
@mejo-
mejo- force-pushed the feat/subscribe branch 2 times, most recently from db59a0f to 7b22b1e Compare June 1, 2026 16:07
@mejo-

mejo- commented Jun 1, 2026

Copy link
Copy Markdown
Member Author

Hi Jonas, I think that the location you've chosen makes sense, I would maybe do it like in Talk though, using a sub-action-menu, so we have more space to be clear with labels and icons.

Great idea @marcoambrosini. Implemented now, see the updated screenshots.

@mejo-
mejo- requested a review from marcoambrosini June 1, 2026 16:07

@marcoambrosini marcoambrosini left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🥳 really nice!

@mejo-
mejo- force-pushed the feat/subscribe branch from 7b22b1e to 4ca5049 Compare June 2, 2026 09:11
@mejo- mejo- moved this from 🏗️ In progress to 👀 In review in 📝 Productivity team Jun 2, 2026
@blizzz

blizzz commented Jun 2, 2026

Copy link
Copy Markdown
Member

I wonder whether adding/removing members shall trigger a notification as well. And how about tagging/untagging pages etc.?
Also, so far there's only three states: "all changes", "@-mention only" (the default) and "off" (no notifications at all). I wonder whether we want to make this more fine-grained, but maybe that's something for a follow-up later on.

That might be worthy activity information, but I am doubtful whether they are worth to create a notification. I would keep it as is for now. (Tagging might probably also need to discriminate between tag types and user privileges if it was implemented 🤔)

@max-nextcloud max-nextcloud self-assigned this Jun 13, 2026
mejo- added 3 commits July 13, 2026 10:51
Sends notifications if pages got updated or deleted. Doesn't send
notifications whne a page got created on purpose as usually pages get
renamed straight after they got created.

Fixes: #317

Signed-off-by: Jonas <jonas@freesources.org>
Requires to install composer in Docker container as notifications app
has run-time PHP dependencies.

Signed-off-by: Jonas <jonas@freesources.org>
Adds a submenu to NcActionsCollectivesActions for selecting the
notification level, like it's done in Nextcloud Talk.

Signed-off-by: Jonas <jonas@freesources.org>

@max-nextcloud max-nextcloud left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All in all looks good. Just a few minor comments.
Have not tested it yet though.

export function setCollectiveUserSettingShowMembers(collectiveId, showMembers) {
return axios.put(
collectiveUserSettingsApiUrl(collectiveId, 'showMembers'),
collectiveUserSettingsApiUrl(collectiveId, ['showMembers']),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The 'showMembers' part should not need to be an array.

I think collectiveUserSettingsApiUrl is missing ...parts in the call to apiUrl. Also the type anotation for apiUrl might be off.

Comment on lines +50 to +70
// Collect direct user member IDs
$memberUserIds = [];
foreach ($circle->getMembers() as $member) {
// TODO: also notify indirect circle/team members
if ($member->getUserType() === Member::TYPE_USER) {
$memberUserIds[] = $member->getUserId();
}
}

if (empty($memberUserIds)) {
return;
}

// Fetch all user settings for this collective in one query
$allSettings = $this->settingsMapper->findByCollectiveId($collective->getId());
$notifyUserIds = [];
foreach ($allSettings as $setting) {
if ($setting->getSetting('notify') === CollectiveUserSettings::NOTIFY_ALL) {
$notifyUserIds[] = $setting->getUserId();
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we could address the indirect members right away:

Suggested change
// Collect direct user member IDs
$memberUserIds = [];
foreach ($circle->getMembers() as $member) {
// TODO: also notify indirect circle/team members
if ($member->getUserType() === Member::TYPE_USER) {
$memberUserIds[] = $member->getUserId();
}
}
if (empty($memberUserIds)) {
return;
}
// Fetch all user settings for this collective in one query
$allSettings = $this->settingsMapper->findByCollectiveId($collective->getId());
$notifyUserIds = [];
foreach ($allSettings as $setting) {
if ($setting->getSetting('notify') === CollectiveUserSettings::NOTIFY_ALL) {
$notifyUserIds[] = $setting->getUserId();
}
}
// Collect direct user member IDs in one query
$memberUserIds = [];
foreach ($circle->getMembers() as $member) {
if ($member->getUserType() === Member::TYPE_USER) {
$memberUserIds[] = $member->getUserId();
}
}
// Fetch all user settings for this collective in one query
$allSettings = $this->settingsMapper->findByCollectiveId($collective->getId());
$notifyUserIds = [];
foreach ($allSettings as $setting) {
if ($setting->getSetting('notify') === CollectiveUserSettings::NOTIFY_ALL) {
$userId = $setting->getUserId();
// Skip acting user
if ($userId === $actingUserId) {
continue;
}
if (in_array($userId, $memberUserIds, true)) {
$notifyUserIds[] = $setting->getUserId();
continue;
}
// Check for indirect membership
$circles = $this->circleHelper->getCircles($userId);
$circleIds = array_map(static fn ($circle) => $circle->getSingleId(), $circles);
if (in_array($collective->getCircleId(), $circleIds, true)) {
$notifyUserIds[] = $setting->getUserId();
}
}
}

Comment on lines +97 to +105
foreach ($memberUserIds as $userId) {
// Skip acting and non-notify users
if ($userId === $actingUserId) {
continue;
}
if (!in_array($userId, $notifyUserIds, true)) {
continue;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

With the change proposed above we only need to iterate over $notifyUserIds as group membership is already accounted for.

Suggested change
foreach ($memberUserIds as $userId) {
// Skip acting and non-notify users
if ($userId === $actingUserId) {
continue;
}
if (!in_array($userId, $notifyUserIds, true)) {
continue;
}
foreach ($notifyUserIds as $userId) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review enhancement New feature or request

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

Notifications for the members of a collective

4 participants