From a2106b4d93a1eec16e9d93f87d8b608acf387a8d Mon Sep 17 00:00:00 2001
From: Marie <marie@kaifa.ch>
Date: Tue, 20 Feb 2024 07:03:26 +0100
Subject: [PATCH 1/4] add: edited notification

---
 locales/en-US.yml                             |  1 +
 locales/index.d.ts                            |  4 ++
 locales/ja-JP.yml                             |  1 +
 .../backend/src/core/GlobalEventService.ts    |  1 +
 packages/backend/src/core/NoteEditService.ts  | 61 ++++---------------
 .../entities/NotificationEntityService.ts     |  4 +-
 packages/backend/src/models/Notification.ts   |  6 ++
 packages/backend/src/models/Webhook.ts        |  2 +-
 .../src/models/json-schema/notification.ts    | 25 ++++++++
 .../api/endpoints/i/notifications-grouped.ts  |  2 +-
 .../server/api/endpoints/i/notifications.ts   |  2 +-
 .../src/components/MkNotification.vue         | 11 +++-
 packages/misskey-js/src/autogen/types.ts      | 21 +++++--
 packages/misskey-js/src/consts.ts             |  2 +-
 packages/misskey-js/src/streaming.types.ts    |  1 +
 .../sw/src/scripts/create-notification.ts     | 14 +++++
 packages/sw/src/sw.ts                         |  3 +
 17 files changed, 99 insertions(+), 62 deletions(-)

diff --git a/locales/en-US.yml b/locales/en-US.yml
index 5d0d4982fe..67791c98ae 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -2334,6 +2334,7 @@ _notification:
   reactedBySomeUsers: "{n} users reacted"
   renotedBySomeUsers: "Boosted by {n} users"
   followedBySomeUsers: "Followed by {n} users"
+  edited: "Note got edited"
   _types:
     all: "All"
     note: "New notes"
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 11beff971d..30ead15e13 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -9048,6 +9048,10 @@ export interface Locale extends ILocale {
          * アンケートの結果が出ました
          */
         "pollEnded": string;
+        /**
+         * 注記が編集されました
+         */
+        "edited": string;
         /**
          * 新しい投稿
          */
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4c433e7254..c01a6d3860 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2389,6 +2389,7 @@ _notification:
   youReceivedFollowRequest: "フォローリクエストが来ました"
   yourFollowRequestAccepted: "フォローリクエストが承認されました"
   pollEnded: "アンケートの結果が出ました"
+  edited: "注記が編集されました"
   newNote: "新しい投稿"
   unreadAntennaNote: "アンテナ {name}"
   roleAssigned: "ロールが付与されました"
diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts
index ab87bf9dee..e568cbf646 100644
--- a/packages/backend/src/core/GlobalEventService.ts
+++ b/packages/backend/src/core/GlobalEventService.ts
@@ -96,6 +96,7 @@ export interface MainEventTypes {
 	announcementCreated: {
 		announcement: Packed<'Announcement'>;
 	};
+	edited: Packed<'Note'>;
 }
 
 export interface DriveEventTypes {
diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts
index b137295b0b..6a469c9634 100644
--- a/packages/backend/src/core/NoteEditService.ts
+++ b/packages/backend/src/core/NoteEditService.ts
@@ -52,7 +52,7 @@ import { isReply } from '@/misc/is-reply.js';
 import { trackPromise } from '@/misc/promise-tracker.js';
 import { isUserRelated } from '@/misc/is-user-related.js';
 
-type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
+type NotificationType = 'reply' | 'renote' | 'quote' | 'mention' | 'edited';
 
 class NotificationManager {
 	private notifier: { id: MiUser['id']; };
@@ -586,7 +586,7 @@ export class NoteEditService implements OnApplicationShutdown {
 			}
 
 			// Pack the note
-			const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true });
+			const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true, withReactionAndUserPairCache: true });
 			if (data.poll != null) {
 				this.globalEventService.publishNoteStream(note.id, 'updated', {
 					cw: note.cw,
@@ -612,7 +612,7 @@ export class NoteEditService implements OnApplicationShutdown {
 
 			const nm = new NotificationManager(this.mutingsRepository, this.notificationService, user, note);
 
-			await this.createMentionedEvents(mentionedUsers, note, nm);
+			//await this.createMentionedEvents(mentionedUsers, note, nm);
 
 			// If has in reply to note
 			if (data.reply) {
@@ -634,12 +634,12 @@ export class NoteEditService implements OnApplicationShutdown {
 					const muted = isUserRelated(note, userIdsWhoMeMuting);
 
 					if (!isThreadMuted && !muted) {
-						nm.push(data.reply.userId, 'reply');
-						this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
+						nm.push(data.reply.userId, 'edited');
+						this.globalEventService.publishMainStream(data.reply.userId, 'edited', noteObj);
 
-						const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply'));
+						const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('edited'));
 						for (const webhook of webhooks) {
-							this.queueService.webhookDeliver(webhook, 'reply', {
+							this.queueService.webhookDeliver(webhook, 'edited', {
 								note: noteObj,
 							});
 						}
@@ -647,45 +647,6 @@ export class NoteEditService implements OnApplicationShutdown {
 				}
 			}
 
-			// If it is renote
-			if (data.renote) {
-				const type = this.isQuote(data) ? 'quote' : 'renote';
-
-				// Notify
-				if (data.renote.userHost === null) {
-					const isThreadMuted = await this.noteThreadMutingsRepository.exists({
-						where: {
-							userId: data.renote.userId,
-							threadId: data.renote.threadId ?? data.renote.id,
-						},
-					});
-
-					const [
-						userIdsWhoMeMuting,
-					] = data.renote.userId ? await Promise.all([
-						this.cacheService.userMutingsCache.fetch(data.renote.userId),
-					]) : [new Set<string>()];
-
-					const muted = isUserRelated(note, userIdsWhoMeMuting);
-
-					if (!isThreadMuted && !muted) {
-						nm.push(data.renote.userId, type);
-					}
-				}
-
-				// Publish event
-				if ((user.id !== data.renote.userId) && data.renote.userHost === null) {
-					this.globalEventService.publishMainStream(data.renote.userId, 'renote', noteObj);
-
-					const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote'));
-					for (const webhook of webhooks) {
-						this.queueService.webhookDeliver(webhook, 'renote', {
-							note: noteObj,
-						});
-					}
-				}
-			}
-
 			nm.notify();
 
 			//#region AP deliver
@@ -780,17 +741,17 @@ export class NoteEditService implements OnApplicationShutdown {
 				detail: true,
 			});
 
-			this.globalEventService.publishMainStream(u.id, 'mention', detailPackedNote);
+			this.globalEventService.publishMainStream(u.id, 'edited', detailPackedNote);
 
-			const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention'));
+			const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('edited'));
 			for (const webhook of webhooks) {
-				this.queueService.webhookDeliver(webhook, 'mention', {
+				this.queueService.webhookDeliver(webhook, 'edited', {
 					note: detailPackedNote,
 				});
 			}
 
 			// Create notification
-			nm.push(u.id, 'mention');
+			nm.push(u.id, 'edited');
 		}
 	}
 
diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts
index a572fe320c..7664c90491 100644
--- a/packages/backend/src/core/entities/NotificationEntityService.ts
+++ b/packages/backend/src/core/entities/NotificationEntityService.ts
@@ -20,8 +20,8 @@ import type { OnModuleInit } from '@nestjs/common';
 import type { UserEntityService } from './UserEntityService.js';
 import type { NoteEntityService } from './NoteEntityService.js';
 
-const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded'] as (typeof notificationTypes[number])[]);
-const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded']);
+const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'edited'] as (typeof notificationTypes[number])[]);
+const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded', 'edited']);
 
 @Injectable()
 export class NotificationEntityService implements OnModuleInit {
diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts
index df88b99636..4ed71a106c 100644
--- a/packages/backend/src/models/Notification.ts
+++ b/packages/backend/src/models/Notification.ts
@@ -107,6 +107,12 @@ export type MiNotification = {
 	type: 'test';
 	id: string;
 	createdAt: string;
+} | {
+	type: 'edited';
+	id: string;
+	createdAt: string;
+	notifierId: MiUser['id'];
+	noteId: MiNote['id'];
 };
 
 export type MiGroupedNotification = MiNotification | {
diff --git a/packages/backend/src/models/Webhook.ts b/packages/backend/src/models/Webhook.ts
index db24c03b3d..2a727f86fd 100644
--- a/packages/backend/src/models/Webhook.ts
+++ b/packages/backend/src/models/Webhook.ts
@@ -7,7 +7,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
 import { id } from './util/id.js';
 import { MiUser } from './User.js';
 
-export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction'] as const;
+export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction', 'edited'] as const;
 
 @Entity('webhook')
 export class MiWebhook {
diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts
index b4c4442758..3f31cc47ee 100644
--- a/packages/backend/src/models/json-schema/notification.ts
+++ b/packages/backend/src/models/json-schema/notification.ts
@@ -318,6 +318,31 @@ export const packedNotificationSchema = {
 				optional: false, nullable: false,
 			},
 		},
+	}, {
+		type: 'object',
+		properties: {
+			...baseSchema.properties,
+			type: {
+				type: 'string',
+				optional: false, nullable: false,
+				enum: ['edited'],
+			},
+			user: {
+				type: 'object',
+				ref: 'UserLite',
+				optional: false, nullable: false,
+			},
+			userId: {
+				type: 'string',
+				optional: false, nullable: false,
+				format: 'id',
+			},
+			note: {
+				type: 'object',
+				ref: 'Note',
+				optional: false, nullable: false,
+			},
+		},
 	}, {
 		type: 'object',
 		properties: {
diff --git a/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts b/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts
index 703808d279..7fcf467030 100644
--- a/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts
+++ b/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts
@@ -164,7 +164,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			groupedNotifications = groupedNotifications.slice(0, ps.limit);
 
 			const noteIds = groupedNotifications
-				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote'> => ['mention', 'reply', 'quote'].includes(notification.type))
+				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'edited' | 'quote'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
 				.map(notification => notification.noteId!);
 
 			if (noteIds.length > 0) {
diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts
index 52b6749e3f..8d8cde1cea 100644
--- a/packages/backend/src/server/api/endpoints/i/notifications.ts
+++ b/packages/backend/src/server/api/endpoints/i/notifications.ts
@@ -113,7 +113,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			}
 
 			const noteIds = notifications
-				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote'> => ['mention', 'reply', 'quote'].includes(notification.type))
+				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'edited' | 'quote'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
 				.map(notification => notification.noteId);
 
 			if (noteIds.length > 0) {
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index e39b996fd9..816c0d4842 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <template>
 <div :class="$style.root">
 	<div :class="$style.head">
-		<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
+		<MkAvatar v-if="['pollEnded', 'note', 'edited'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
 		<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
 		<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
 		<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ph-rocket-launch ph-bold ph-lg" style="line-height: 1;"></i></div>
@@ -25,6 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				[$style.t_pollEnded]: notification.type === 'pollEnded',
 				[$style.t_achievementEarned]: notification.type === 'achievementEarned',
 				[$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null,
+				[$style.t_pollEnded]: notification.type === 'edited',
 			}]"
 		>
 			<i v-if="notification.type === 'follow'" class="ph-plus ph-bold ph-lg"></i>
@@ -40,6 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<img v-if="notification.role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/>
 				<i v-else class="ph-seal-check ph-bold ph-lg"></i>
 			</template>
+			<i v-else-if="notification.type === 'edited'" class="ph-pencil ph-bold ph-lg"></i>
 			<!-- notification.reaction が null になることはまずないが、ここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
 			<MkReactionIcon
 				v-else-if="notification.type === 'reaction'"
@@ -61,6 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
 			<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
 			<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
+			<span v-else-if="notification.type === 'edited'">{{ i18n.ts._notification.edited }}</span>
 			<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
 		</header>
 		<div>
@@ -131,6 +134,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<MkAvatar :class="$style.reactionsItemAvatar" :user="user" link preview/>
 				</div>
 			</div>
+
+			<MkA v-else-if="notification.type === 'edited'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
+				<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
+				<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
+				<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
+			</MkA>
 		</div>
 	</div>
 </div>
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index e53ad4b589..6c0c6d249f 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4273,6 +4273,17 @@ export type components = {
       body: string;
       header: string;
       icon: string;
+    } | {
+      /** Format: id */
+      id: string;
+      /** Format: date-time */
+      createdAt: string;
+      /** @enum {string} */
+      type: 'edited';
+      user: components['schemas']['UserLite'];
+      /** Format: id */
+      userId: string;
+      note: components['schemas']['Note'];
     } | {
       /** Format: id */
       id: string;
@@ -19511,7 +19522,7 @@ export type operations = {
           url: string;
           /** @default */
           secret?: string;
-          on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
+          on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
         };
       };
     };
@@ -19525,7 +19536,7 @@ export type operations = {
             /** Format: misskey:id */
             userId: string;
             name: string;
-            on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
+            on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
             url: string;
             secret: string;
             active: boolean;
@@ -19584,7 +19595,7 @@ export type operations = {
               /** Format: misskey:id */
               userId: string;
               name: string;
-              on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
+              on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
               url: string;
               secret: string;
               active: boolean;
@@ -19651,7 +19662,7 @@ export type operations = {
             /** Format: misskey:id */
             userId: string;
             name: string;
-            on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
+            on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
             url: string;
             secret: string;
             active: boolean;
@@ -19709,7 +19720,7 @@ export type operations = {
           url: string;
           /** @default */
           secret?: string;
-          on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
+          on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
           active: boolean;
         };
       };
diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts
index 0748d9863e..57d35e0ec2 100644
--- a/packages/misskey-js/src/consts.ts
+++ b/packages/misskey-js/src/consts.ts
@@ -1,4 +1,4 @@
-export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const;
+export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned', 'edited'] as const;
 
 export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;
 
diff --git a/packages/misskey-js/src/streaming.types.ts b/packages/misskey-js/src/streaming.types.ts
index 9a2b814d20..1e9750d670 100644
--- a/packages/misskey-js/src/streaming.types.ts
+++ b/packages/misskey-js/src/streaming.types.ts
@@ -56,6 +56,7 @@ export type Channels = {
 			readAntenna: (payload: Antenna) => void;
 			receiveFollowRequest: (payload: User) => void;
 			announcementCreated: (payload: AnnouncementCreated) => void;
+			edited: (payload: Note) => void;
 		};
 		receives: null;
 	};
diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts
index 3e2fb16ec0..7e1350dff9 100644
--- a/packages/sw/src/scripts/create-notification.ts
+++ b/packages/sw/src/scripts/create-notification.ts
@@ -232,6 +232,20 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
 						data,
 					}];
 
+				case 'edited':
+					return [t('_notification.youGotReply', { name: getUserName(data.body.user) }), {
+						body: data.body.note.text ?? '',
+						icon: data.body.user.avatarUrl,
+						badge: iconUrl('messages'),
+						data,
+						actions: [
+							{
+								action: 'reply',
+								title: t('_notification.edited'),
+							},
+						],
+					}];
+
 				default:
 					return null;
 			}
diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts
index 46fe9fc90f..c38419eadc 100644
--- a/packages/sw/src/sw.ts
+++ b/packages/sw/src/sw.ts
@@ -133,6 +133,9 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv
 					case 'showFollowRequests':
 						client = await swos.openClient('push', '/my/follow-requests', loginId);
 						break;
+					case 'edited':
+						if ('note' in data.body) client = await swos.openPost({ reply: data.body.note }, loginId);
+						break;
 					default:
 						switch (data.body.type) {
 							case 'receiveFollowRequest':
-- 
GitLab


From b48996dd1b3577f8ea190929a46edbf22c7aa8c7 Mon Sep 17 00:00:00 2001
From: Marie <marie@kaifa.ch>
Date: Tue, 20 Feb 2024 13:15:39 +0100
Subject: [PATCH 2/4] fix: order, SW notification text

---
 .../src/server/api/endpoints/i/notifications-grouped.ts   | 2 +-
 .../backend/src/server/api/endpoints/i/notifications.ts   | 2 +-
 packages/sw/src/scripts/create-notification.ts            | 8 +-------
 3 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts b/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts
index 7fcf467030..d400cbc1c9 100644
--- a/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts
+++ b/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts
@@ -164,7 +164,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			groupedNotifications = groupedNotifications.slice(0, ps.limit);
 
 			const noteIds = groupedNotifications
-				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'edited' | 'quote'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
+				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote' | 'edited'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
 				.map(notification => notification.noteId!);
 
 			if (noteIds.length > 0) {
diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts
index 8d8cde1cea..d9404ea9c5 100644
--- a/packages/backend/src/server/api/endpoints/i/notifications.ts
+++ b/packages/backend/src/server/api/endpoints/i/notifications.ts
@@ -113,7 +113,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			}
 
 			const noteIds = notifications
-				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'edited' | 'quote'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
+				.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote' | 'edited'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
 				.map(notification => notification.noteId);
 
 			if (noteIds.length > 0) {
diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts
index 7e1350dff9..32b12f4b4f 100644
--- a/packages/sw/src/scripts/create-notification.ts
+++ b/packages/sw/src/scripts/create-notification.ts
@@ -233,17 +233,11 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
 					}];
 
 				case 'edited':
-					return [t('_notification.youGotReply', { name: getUserName(data.body.user) }), {
+					return [t('_notification.edited', { name: getUserName(data.body.user) }), {
 						body: data.body.note.text ?? '',
 						icon: data.body.user.avatarUrl,
 						badge: iconUrl('messages'),
 						data,
-						actions: [
-							{
-								action: 'reply',
-								title: t('_notification.edited'),
-							},
-						],
 					}];
 
 				default:
-- 
GitLab


From aa1bad7bc5140ad400b0092d8faa94ef5c6eea1e Mon Sep 17 00:00:00 2001
From: dakkar <dakkar@thenautilus.net>
Date: Tue, 20 Feb 2024 15:04:03 +0000
Subject: [PATCH 3/4] probably better ja-JP translation

---
 locales/ja-JP.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index c01a6d3860..db3ea6c653 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2389,7 +2389,7 @@ _notification:
   youReceivedFollowRequest: "フォローリクエストが来ました"
   yourFollowRequestAccepted: "フォローリクエストが承認されました"
   pollEnded: "アンケートの結果が出ました"
-  edited: "注記が編集されました"
+  edited: "投稿が編集されました"
   newNote: "新しい投稿"
   unreadAntennaNote: "アンテナ {name}"
   roleAssigned: "ロールが付与されました"
-- 
GitLab


From cb1eaa2d856e69de2855609104bd51bca73e5b44 Mon Sep 17 00:00:00 2001
From: dakkar <dakkar@thenautilus.net>
Date: Tue, 20 Feb 2024 15:06:07 +0000
Subject: [PATCH 4/4] comment on the re-use of `t_pollEnded`

---
 packages/frontend/src/components/MkNotification.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index 816c0d4842..562cc38bf3 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				[$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null,
 				[$style.t_pollEnded]: notification.type === 'edited',
 			}]"
-		>
+		> <!-- we re-use t_pollEnded for "edited" instead of making an identical style -->
 			<i v-if="notification.type === 'follow'" class="ph-plus ph-bold ph-lg"></i>
 			<i v-else-if="notification.type === 'receiveFollowRequest'" class="ph-clock ph-bold ph-lg"></i>
 			<i v-else-if="notification.type === 'followRequestAccepted'" class="ph-check ph-bold ph-lg"></i>
-- 
GitLab