Skip to content

Commit 39d6af1

Browse files
enhance: 通知の履歴をリセットできるように (#13335)
* enhance: 通知の履歴をリセットできるように * Update Changelog * 通知欄も連動して更新するように * revert some changes * Update CHANGELOG.md * Remove unused part * fix
1 parent ec18991 commit 39d6af1

File tree

15 files changed

+139
-1
lines changed

15 files changed

+139
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- Enhance: サーバーごとにモデレーションノートを残せるように
1919
- Enhance: コンディショナルロールの条件に「マニュアルロールへのアサイン」を追加
2020
- Enhance: 通知の受信設定に「フォロー中またはフォロワー」を追加
21+
- Enhance: 通知の履歴をリセットできるように
2122

2223
### Client
2324
- Enhance: ノート作成画面のファイル添付メニューの区切り線の位置を調整

locales/index.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -8913,6 +8913,10 @@ export interface Locale extends ILocale {
89138913
* {n}人にフォローされました
89148914
*/
89158915
"followedBySomeUsers": ParameterizedString<"n">;
8916+
/**
8917+
* 通知の履歴をリセットする
8918+
*/
8919+
"flushNotification": string;
89168920
"_types": {
89178921
/**
89188922
* すべて

locales/ja-JP.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2356,6 +2356,7 @@ _notification:
23562356
reactedBySomeUsers: "{n}人がリアクションしました"
23572357
renotedBySomeUsers: "{n}人がリノートしました"
23582358
followedBySomeUsers: "{n}人にフォローされました"
2359+
flushNotification: "通知の履歴をリセットする"
23592360

23602361
_types:
23612362
all: "すべて"

packages/backend/src/core/GlobalEventService.ts

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export interface MainEventTypes {
6969
file: Packed<'DriveFile'>;
7070
};
7171
readAllNotifications: undefined;
72+
notificationFlushed: undefined;
7273
unreadNotification: Packed<'Notification'>;
7374
unreadMention: MiNote['id'];
7475
readAllUnreadMentions: undefined;

packages/backend/src/core/NotificationService.ts

+9
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,15 @@ export class NotificationService implements OnApplicationShutdown {
214214
*/
215215
}
216216

217+
@bindThis
218+
public async flushAllNotifications(userId: MiUser['id']) {
219+
await Promise.all([
220+
this.redisClient.del(`notificationTimeline:${userId}`),
221+
this.redisClient.del(`latestReadNotification:${userId}`),
222+
]);
223+
this.globalEventService.publishMainStream(userId, 'notificationFlushed');
224+
}
225+
217226
@bindThis
218227
public dispose(): void {
219228
this.#shutdownController.abort();

packages/backend/src/server/api/EndpointsModule.ts

+5
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ import * as ep___notes_translate from './endpoints/notes/translate.js';
293293
import * as ep___notes_unrenote from './endpoints/notes/unrenote.js';
294294
import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js';
295295
import * as ep___notifications_create from './endpoints/notifications/create.js';
296+
import * as ep___notifications_flush from './endpoints/notifications/flush.js';
296297
import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js';
297298
import * as ep___notifications_testNotification from './endpoints/notifications/test-notification.js';
298299
import * as ep___pagePush from './endpoints/page-push.js';
@@ -664,6 +665,7 @@ const $notes_translate: Provider = { provide: 'ep:notes/translate', useClass: ep
664665
const $notes_unrenote: Provider = { provide: 'ep:notes/unrenote', useClass: ep___notes_unrenote.default };
665666
const $notes_userListTimeline: Provider = { provide: 'ep:notes/user-list-timeline', useClass: ep___notes_userListTimeline.default };
666667
const $notifications_create: Provider = { provide: 'ep:notifications/create', useClass: ep___notifications_create.default };
668+
const $notifications_flush: Provider = { provide: 'ep:notifications/flush', useClass: ep___notifications_flush.default };
667669
const $notifications_markAllAsRead: Provider = { provide: 'ep:notifications/mark-all-as-read', useClass: ep___notifications_markAllAsRead.default };
668670
const $notifications_testNotification: Provider = { provide: 'ep:notifications/test-notification', useClass: ep___notifications_testNotification.default };
669671
const $pagePush: Provider = { provide: 'ep:page-push', useClass: ep___pagePush.default };
@@ -1039,6 +1041,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
10391041
$notes_unrenote,
10401042
$notes_userListTimeline,
10411043
$notifications_create,
1044+
$notifications_flush,
10421045
$notifications_markAllAsRead,
10431046
$notifications_testNotification,
10441047
$pagePush,
@@ -1408,7 +1411,9 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
14081411
$notes_unrenote,
14091412
$notes_userListTimeline,
14101413
$notifications_create,
1414+
$notifications_flush,
14111415
$notifications_markAllAsRead,
1416+
$notifications_testNotification,
14121417
$pagePush,
14131418
$pages_create,
14141419
$pages_delete,

packages/backend/src/server/api/endpoints.ts

+2
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ import * as ep___notes_translate from './endpoints/notes/translate.js';
293293
import * as ep___notes_unrenote from './endpoints/notes/unrenote.js';
294294
import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js';
295295
import * as ep___notifications_create from './endpoints/notifications/create.js';
296+
import * as ep___notifications_flush from './endpoints/notifications/flush.js';
296297
import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js';
297298
import * as ep___notifications_testNotification from './endpoints/notifications/test-notification.js';
298299
import * as ep___pagePush from './endpoints/page-push.js';
@@ -662,6 +663,7 @@ const eps = [
662663
['notes/unrenote', ep___notes_unrenote],
663664
['notes/user-list-timeline', ep___notes_userListTimeline],
664665
['notifications/create', ep___notifications_create],
666+
['notifications/flush', ep___notifications_flush],
665667
['notifications/mark-all-as-read', ep___notifications_markAllAsRead],
666668
['notifications/test-notification', ep___notifications_testNotification],
667669
['page-push', ep___pagePush],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* SPDX-FileCopyrightText: syuilo and misskey-project
3+
* SPDX-License-Identifier: AGPL-3.0-only
4+
*/
5+
6+
import { Injectable } from '@nestjs/common';
7+
import { Endpoint } from '@/server/api/endpoint-base.js';
8+
import { NotificationService } from '@/core/NotificationService.js';
9+
10+
export const meta = {
11+
tags: ['notifications', 'account'],
12+
13+
requireCredential: true,
14+
15+
kind: 'write:notifications',
16+
} as const;
17+
18+
export const paramDef = {
19+
type: 'object',
20+
properties: {},
21+
required: [],
22+
} as const;
23+
24+
@Injectable()
25+
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
26+
constructor(
27+
private notificationService: NotificationService,
28+
) {
29+
super(meta, paramDef, async (ps, me) => {
30+
this.notificationService.flushAllNotifications(me.id);
31+
});
32+
}
33+
}

packages/frontend/src/components/MkNotifications.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { notificationTypes } from '@/const.js';
3535
import { infoImageUrl } from '@/instance.js';
3636
import { defaultStore } from '@/store.js';
3737
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
38+
import * as Misskey from 'misskey-js';
3839

3940
const props = defineProps<{
4041
excludeTypes?: typeof notificationTypes[number][];
@@ -75,17 +76,19 @@ function reload() {
7576
});
7677
}
7778

78-
let connection;
79+
let connection: Misskey.ChannelConnection<Misskey.Channels['main']>;
7980

8081
onMounted(() => {
8182
connection = useStream().useChannel('main');
8283
connection.on('notification', onNotification);
84+
connection.on('notificationFlushed', reload);
8385
});
8486

8587
onActivated(() => {
8688
pagingComponent.value?.reload();
8789
connection = useStream().useChannel('main');
8890
connection.on('notification', onNotification);
91+
connection.on('notificationFlushed', reload);
8992
});
9093

9194
onUnmounted(() => {

packages/frontend/src/pages/settings/notifications.vue

+12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
3535
<FormSection>
3636
<div class="_gaps_m">
3737
<FormLink @click="testNotification">{{ i18n.ts._notification.sendTestNotification }}</FormLink>
38+
<FormLink @click="flushNotification">{{ i18n.ts._notification.flushNotification }}</FormLink>
3839
</div>
3940
</FormSection>
4041
<FormSection>
@@ -114,6 +115,17 @@ function testNotification(): void {
114115
misskeyApi('notifications/test-notification');
115116
}
116117

118+
async function flushNotification() {
119+
const { canceled } = await os.confirm({
120+
type: 'warning',
121+
text: i18n.ts.resetAreYouSure,
122+
});
123+
124+
if (canceled) return;
125+
126+
os.apiWithDialog('notifications/flush');
127+
}
128+
117129
const headerActions = computed(() => []);
118130

119131
const headerTabs = computed(() => []);

packages/misskey-js/etc/misskey-js.api.md

+1
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ export type Channels = {
530530
unreadNotification: (payload: Notification_2) => void;
531531
unreadMention: (payload: Note['id']) => void;
532532
readAllUnreadMentions: () => void;
533+
notificationFlushed: () => void;
533534
unreadSpecifiedNote: (payload: Note['id']) => void;
534535
readAllUnreadSpecifiedNotes: () => void;
535536
readAllAntennas: () => void;

packages/misskey-js/src/autogen/apiClientJSDoc.ts

+11
Original file line numberDiff line numberDiff line change
@@ -3195,6 +3195,17 @@ declare module '../api.js' {
31953195
credential?: string | null,
31963196
): Promise<SwitchCaseResponseType<E, P>>;
31973197

3198+
/**
3199+
* No description provided.
3200+
*
3201+
* **Credential required**: *Yes* / **Permission**: *write:notifications*
3202+
*/
3203+
request<E extends 'notifications/flush', P extends Endpoints[E]['req']>(
3204+
endpoint: E,
3205+
params: P,
3206+
credential?: string | null,
3207+
): Promise<SwitchCaseResponseType<E, P>>;
3208+
31983209
/**
31993210
* No description provided.
32003211
*

packages/misskey-js/src/autogen/endpoint.ts

+1
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ export type Endpoints = {
841841
'notes/unrenote': { req: NotesUnrenoteRequest; res: EmptyResponse };
842842
'notes/user-list-timeline': { req: NotesUserListTimelineRequest; res: NotesUserListTimelineResponse };
843843
'notifications/create': { req: NotificationsCreateRequest; res: EmptyResponse };
844+
'notifications/flush': { req: EmptyRequest; res: EmptyResponse };
844845
'notifications/mark-all-as-read': { req: EmptyRequest; res: EmptyResponse };
845846
'notifications/test-notification': { req: EmptyRequest; res: EmptyResponse };
846847
'page-push': { req: PagePushRequest; res: EmptyResponse };

packages/misskey-js/src/autogen/types.ts

+53
Original file line numberDiff line numberDiff line change
@@ -2770,6 +2770,15 @@ export type paths = {
27702770
*/
27712771
post: operations['notifications/create'];
27722772
};
2773+
'/notifications/flush': {
2774+
/**
2775+
* notifications/flush
2776+
* @description No description provided.
2777+
*
2778+
* **Credential required**: *Yes* / **Permission**: *write:notifications*
2779+
*/
2780+
post: operations['notifications/flush'];
2781+
};
27732782
'/notifications/mark-all-as-read': {
27742783
/**
27752784
* notifications/mark-all-as-read
@@ -22056,6 +22065,50 @@ export type operations = {
2205622065
};
2205722066
};
2205822067
};
22068+
/**
22069+
* notifications/flush
22070+
* @description No description provided.
22071+
*
22072+
* **Credential required**: *Yes* / **Permission**: *write:notifications*
22073+
*/
22074+
'notifications/flush': {
22075+
responses: {
22076+
/** @description OK (without any results) */
22077+
204: {
22078+
content: never;
22079+
};
22080+
/** @description Client error */
22081+
400: {
22082+
content: {
22083+
'application/json': components['schemas']['Error'];
22084+
};
22085+
};
22086+
/** @description Authentication error */
22087+
401: {
22088+
content: {
22089+
'application/json': components['schemas']['Error'];
22090+
};
22091+
};
22092+
/** @description Forbidden error */
22093+
403: {
22094+
content: {
22095+
'application/json': components['schemas']['Error'];
22096+
};
22097+
};
22098+
/** @description I'm Ai */
22099+
418: {
22100+
content: {
22101+
'application/json': components['schemas']['Error'];
22102+
};
22103+
};
22104+
/** @description Internal server error */
22105+
500: {
22106+
content: {
22107+
'application/json': components['schemas']['Error'];
22108+
};
22109+
};
22110+
};
22111+
};
2205922112
/**
2206022113
* notifications/mark-all-as-read
2206122114
* @description No description provided.

packages/misskey-js/src/streaming.types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export type Channels = {
4040
unreadNotification: (payload: Notification) => void;
4141
unreadMention: (payload: Note['id']) => void;
4242
readAllUnreadMentions: () => void;
43+
notificationFlushed: () => void;
4344
unreadSpecifiedNote: (payload: Note['id']) => void;
4445
readAllUnreadSpecifiedNotes: () => void;
4546
readAllAntennas: () => void;

0 commit comments

Comments
 (0)