Skip to content

enhance: ファイルが添付されたノートのみ通知する設定を追加#17737

Open
4ster1sk wants to merge 2 commits into
misskey-dev:developfrom
4ster1sk:enhance/notify-withfile
Open

enhance: ファイルが添付されたノートのみ通知する設定を追加#17737
4ster1sk wants to merge 2 commits into
misskey-dev:developfrom
4ster1sk:enhance/notify-withfile

Conversation

@4ster1sk

Copy link
Copy Markdown
Contributor

What

投稿通知設定に「ファイル付き投稿のみ通知」のオプションを追加しました。
これにより「ファイルが添付されたノート」のみの通知を受け取ることができるようになります

Why

ファイルが付いた投稿だけ気軽にチェックしたい人向けに、フィルタできる選択肢を増やしました。

Additional info (optional)

Checklist

  • Read the contribution guide
  • Test working in a local environment
  • (If needed) Add story of storybook
  • (If needed) Update CHANGELOG.md
  • (If possible) Add tests

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jul 18, 2026
@github-actions github-actions Bot added packages/frontend Client side specific issue/PR packages/backend Server side specific issue/PR packages/misskey-js packages/backend:test labels Jul 18, 2026
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 194fd126-608a-4df9-b864-c35aac76bb0a

📥 Commits

Reviewing files that changed from the base of the PR and between d4db197 and 6d62ff7.

📒 Files selected for processing (1)
  • packages/backend/test/e2e/note-notify.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/backend/test/e2e/note-notify.ts

📝 Walkthrough

Walkthrough

Following notifications now support normal, withFile, and none modes. Backend delivery, API schemas, client types, frontend menus, Japanese labels, and end-to-end tests were updated accordingly.

Changes

Following notification modes

Layer / File(s) Summary
Notification mode contracts
packages/backend/src/models/Following.ts, packages/backend/src/models/json-schema/user.ts, packages/backend/src/server/api/endpoints/following/..., packages/misskey-js/src/autogen/types.ts
The withFile mode is accepted by following APIs, represented in following and user schemas, and included in generated client types.
Conditional notification dispatch
packages/backend/src/core/NoteCreateService.ts, packages/backend/test/e2e/note-notify.ts
Followings using withFile receive notifications only for notes with attached files; tests cover filtering, file behavior, and pagination.
Notification preference controls
packages/frontend/src/pages/settings/notifications.vue, packages/frontend/src/utility/get-user-menu.ts
Notification menus provide radio options for normal, withFile, and none, updating the selected following preference.
Notification labels and locale contract
locales/ja-JP.yml, packages/i18n/src/autogen/locale.ts
Japanese notification labels include all-note and file-only options, with updated wording for disabling notifications.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant NotificationMenu
  participant FollowingUpdate
  participant NoteCreateService
  participant NotificationStore
  User->>NotificationMenu: Select notification mode
  NotificationMenu->>FollowingUpdate: Update notify preference
  NoteCreateService->>NotificationStore: Create notification for matching notes
Loading

Poem

A rabbit hops through settings bright,
Three notification paths take flight.
All notes, files, or none at all,
The backend listens when they call.
“Thump thump!” tests confirm it right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding a notification setting for notes with attached files only.
Description check ✅ Passed The description follows the template and includes What, Why, and Checklist sections with the core intent clearly stated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

このPRによるapi.jsonの差分

差分はこちら
--- base
+++ head
@@ -50263,6 +50263,7 @@
                     "type": "string",
                     "enum": [
                       "normal",
+                      "withFile",
                       "none"
                     ]
                   },
@@ -50472,6 +50473,7 @@
                     "type": "string",
                     "enum": [
                       "normal",
+                      "withFile",
                       "none"
                     ]
                   },
@@ -88844,6 +88846,7 @@
             "type": "string",
             "enum": [
               "normal",
+              "withFile",
               "none"
             ]
           },

Get diff files from Workflow Page

@codecov

codecov Bot commented Jul 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 9.09091% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 26.40%. Comparing base (c29a3d9) to head (6d62ff7).
⚠️ Report is 104 commits behind head on develop.

Files with missing lines Patch % Lines
packages/frontend/src/utility/get-user-menu.ts 0.00% 8 Missing ⚠️
packages/backend/src/core/NoteCreateService.ts 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           develop   #17737       +/-   ##
============================================
+ Coverage    15.00%   26.40%   +11.39%     
============================================
  Files          248     1183      +935     
  Lines        12402    40321    +27919     
  Branches      4224    11135     +6911     
============================================
+ Hits          1861    10647     +8786     
- Misses        8239    23797    +15558     
- Partials      2302     5877     +3575     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/backend/src/core/NoteCreateService.ts (1)

773-790: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Do not fetch withFile followers for text-only notes.

Text-only posts now load and iterate file-only followers even though they can never receive a notification. Compute hasFiles before the query and filter to normal unless files exist.

Suggested change
 if (data.reply == null) {
+	const hasFiles = note.fileIds.length > 0;
 	this.followingsRepository.findBy({
 		followeeId: user.id,
-		notify: In(['normal', 'withFile']),
+		notify: hasFiles ? In(['normal', 'withFile']) : 'normal',
 	}).then(async followings => {
 		if (note.visibility !== 'specified') {
 			const isPureRenote = this.isRenote(data) && !this.isQuote(data) ? true : false;
-			const hasFiles = data.files != null && data.files.length > 0;
 			for (const following of followings) {
 				// ...
-				if (following.notify === 'normal' || (following.notify === 'withFile' && hasFiles)) {
-					this.notificationService.createNotification(/* ... */);
-				}
+				this.notificationService.createNotification(/* ... */);
 			}
 		}
 	});
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/backend/src/core/NoteCreateService.ts` around lines 773 - 790,
Compute hasFiles before the followings query in the note creation flow, then
query with notify restricted to normal for text-only notes and normal/withFile
when files exist. Keep the existing notification iteration and filtering in the
visible followings callback, including isRenoteMuted handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/backend/test/e2e/note-notify.ts`:
- Around line 168-190: Replace both fixed setTimeout(100) delays in the note
notification test with bounded polling of i/notifications using vi.waitFor or
the test’s established equivalent. Ensure the first poll confirms no
notification for the file-less note before proceeding, and the second waits
until the file-backed note notification appears, while preserving the existing
assertions and API calls.

---

Nitpick comments:
In `@packages/backend/src/core/NoteCreateService.ts`:
- Around line 773-790: Compute hasFiles before the followings query in the note
creation flow, then query with notify restricted to normal for text-only notes
and normal/withFile when files exist. Keep the existing notification iteration
and filtering in the visible followings callback, including isRenoteMuted
handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a5e4f16-551d-4e27-a8cf-b5529c87ba0f

📥 Commits

Reviewing files that changed from the base of the PR and between fca7859 and d4db197.

📒 Files selected for processing (11)
  • locales/ja-JP.yml
  • packages/backend/src/core/NoteCreateService.ts
  • packages/backend/src/models/Following.ts
  • packages/backend/src/models/json-schema/user.ts
  • packages/backend/src/server/api/endpoints/following/update-all.ts
  • packages/backend/src/server/api/endpoints/following/update.ts
  • packages/backend/test/e2e/note-notify.ts
  • packages/frontend/src/pages/settings/notifications.vue
  • packages/frontend/src/utility/get-user-menu.ts
  • packages/i18n/src/autogen/locale.ts
  • packages/misskey-js/src/autogen/types.ts

Comment on lines +168 to +190
// redisに追加されるのを待つ
await setTimeout(100);

const beforeRes = await api('i/notifications', {}, alice);
assert.strictEqual(beforeRes.status, 200);
const noteNotifsBefore = beforeRes.body.filter((n: { type: string; note?: { id: string } }) =>
n.type === 'note' && n.note?.id === textOnlyRes.body.createdNote.id,
);
assert.strictEqual(noteNotifsBefore.length, 0, 'ファイルなし投稿で通知が来てしまった');

// --- ケース2: ファイル付き投稿 → 通知が来ること ---
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg');

const fileNoteRes = await api('notes/create', {
fileIds: [file.id],
}, bob);
assert.strictEqual(fileNoteRes.status, 200);
assert.deepStrictEqual(fileNoteRes.body.createdNote.fileIds, [file.id]);

// redisに追加されるのを待つ
await setTimeout(100);

const res = await api('i/notifications', {}, alice);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- note-notify.ts around cited lines ---'
sed -n '130,230p' packages/backend/test/e2e/note-notify.ts

echo
echo '--- search for notification polling / retry helpers ---'
rg -n "setTimeout\(100\)|poll|retry|waitFor|eventually|notifications" packages/backend/test -g '*.ts'

Repository: misskey-dev/misskey

Length of output: 34789


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- file stats ---'
wc -l packages/backend/test/e2e/note-notify.ts

echo
echo '--- candidate helper files ---'
git ls-files packages/backend/test | sed -n '1,120p'

Repository: misskey-dev/misskey

Length of output: 5135


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- search for setTimeout imports/usages in backend e2e tests ---'
rg -n "import .*setTimeout|setTimeout\(" packages/backend/test/e2e -g '*.ts'

echo
echo '--- inspect test utilities for polling helpers ---'
rg -n "waitFor|retry|poll|sleep|delay|settle|promise.*timeout" packages/backend/test packages/backend/src -g '*.ts'

Repository: misskey-dev/misskey

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '150,220p' packages/backend/test/e2e/note-notify.ts

Repository: misskey-dev/misskey

Length of output: 2658


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- note creation notification call sites ---'
rg -n "createNotification\(|notificationService\." packages/backend/src/core/NoteCreateService.ts packages/backend/src/queue packages/backend/src/core -g '*.ts' | sed -n '1,120p'

echo
echo '--- note-notify test imports ---'
sed -n '1,40p' packages/backend/test/e2e/note-notify.ts

Repository: misskey-dev/misskey

Length of output: 5184


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- relevant note create service slice ---'
sed -n '760,860p' packages/backend/src/core/NoteCreateService.ts

echo
echo '--- notification queue / processor slice if any ---'
rg -n "publishNoteStream|queue.*notification|Notification" packages/backend/src/queue packages/backend/src/core -g '*.ts' | sed -n '1,120p'

Repository: misskey-dev/misskey

Length of output: 19021


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '780,840p' packages/backend/src/core/NoteCreateService.ts

Repository: misskey-dev/misskey

Length of output: 2060


Replace the fixed sleeps with polling in packages/backend/test/e2e/note-notify.ts. notes/create queues notification creation asynchronously, so await setTimeout(100) can still read too early or let a late notification race past the negative check. Use vi.waitFor or another bounded wait on i/notifications instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/backend/test/e2e/note-notify.ts` around lines 168 - 190, Replace
both fixed setTimeout(100) delays in the note notification test with bounded
polling of i/notifications using vi.waitFor or the test’s established
equivalent. Ensure the first poll confirms no notification for the file-less
note before proceeding, and the second waits until the file-backed note
notification appears, while preserving the existing assertions and API calls.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

⚙️ Backend Diagnostics Report

Memory: After GC

Metric Base Head Δ median Δ MAD Δ min Δ max
HeapUsed 72.3 MB
± 0 MB
72.3 MB
± 0 MB
$\text{+0 MB}$
$\text{+0\%}$
0 MB $\text{-0.1 MB}$ $\text{+0 MB}$
PSS 282.3 MB
± 1.7 MB
281.2 MB
± 2.1 MB
$\color{green}{\text{-1.2 MB}}$
$\color{green}{\text{-0.4\%}}$
3.9 MB $\color{green}{\text{-11 MB}}$ $\color{orange}{\text{+6.4 MB}}$
USS 263.3 MB
± 1.7 MB
262.3 MB
± 2.1 MB
$\color{green}{\text{-1.2 MB}}$
$\color{green}{\text{-0.4\%}}$
3.9 MB $\color{green}{\text{-11 MB}}$ $\color{orange}{\text{+6.4 MB}}$
External 8.7 MB
± 0 MB
8.7 MB
± 0 MB
0 MB
0%
0 MB 0 MB 0 MB

V8 Heap Snapshot Statistics

Metric Base Head Δ median Δ MAD Δ min Δ max
$\color{gray}{\rule{8pt}{8pt}}$ Total 86 MB
± 7.1 KB
86 MB
± 8.1 KB
$\text{+4.3 KB}$
$\text{+0\%}$
7.5 KB $\text{-58 KB}$ $\text{+15 KB}$
$\color{orange}{\rule{8pt}{8pt}}$ Code28.7% → 28.7%
25 MB 25 MB $\text{+2.9 KB}$ 8 KB $\text{-52 KB}$ $\text{+16 KB}$
$\color{red}{\rule{8pt}{8pt}}$ Strings34.9% → 34.9%
30 MB 30 MB $\text{-388 B}$ 1.6 KB $\text{-12 KB}$ $\text{+4.2 KB}$
$\color{cyan}{\rule{8pt}{8pt}}$ JS arrays4.8% → 4.8%
4.1 MB 4.1 MB 0 B 0 B 0 B 0 B
$\color{green}{\rule{8pt}{8pt}}$ Typed arrays0.6% → 0.6%
533 KB 533 KB 0 B 0 B 0 B 0 B
$\color{yellow}{\rule{8pt}{8pt}}$ System objects2.6% → 2.6%
2.2 MB 2.2 MB $\text{+280 B}$ 1 KB $\text{-3.7 KB}$ $\text{+3.8 KB}$
$\color{violet}{\rule{8pt}{8pt}}$ Other JS objs28.3% → 28.3%
24 MB 24 MB $\text{+12 B}$ 164 B $\text{-4.7 KB}$ $\text{+5 KB}$
$\color{pink}{\rule{8pt}{8pt}}$ Other non-JS objs0% → 0%
39 KB 39 KB 0 B 0 B 0 B 0 B

Download representative heap snapshot: base / head

@4ster1sk
4ster1sk force-pushed the enhance/notify-withfile branch from d4db197 to 6d62ff7 Compare July 18, 2026 01:31
@kakkokari-gtyih

kakkokari-gtyih commented Jul 18, 2026

Copy link
Copy Markdown
Member

non-blocker: (修正ではなく機能追加なので、先にIssueで実装の是非について確認取ったほうが良い可能性はある)

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

Labels

packages/backend:test packages/backend Server side specific issue/PR packages/frontend Client side specific issue/PR packages/misskey-js size:M This PR changes 30-99 lines, ignoring generated files.

Projects

Development

Successfully merging this pull request may close these issues.

2 participants