diff --git a/CHANGELOG.md b/CHANGELOG.md
index d89d81e6ac..2fc561d9aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,10 @@
-
### Client
--
+- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
+- Enhance: リアクション・いいねの総数を表示するように
+- Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
+- Fix: 一部のページ内リンクが正しく動作しない問題を修正
### Server
-
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 6b20134b2d..49688d24ea 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -2338,6 +2338,7 @@ _notification:
sendTestNotification: "Send test notification"
notificationWillBeDisplayedLikeThis: "Notifications look like this"
reactedBySomeUsers: "{n} users reacted"
+ likedBySomeUsers: "{n} users liked"
renotedBySomeUsers: "Renote from {n} users"
followedBySomeUsers: "Followed by {n} users"
flushNotification: "Clear notifications"
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 49d2ad1949..ac4cae7845 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -9089,6 +9089,10 @@ export interface Locale extends ILocale {
* {n}人がリアクションしました
*/
"reactedBySomeUsers": ParameterizedString<"n">;
+ /**
+ * {n}人がいいねしました
+ */
+ "likedBySomeUsers": ParameterizedString<"n">;
/**
* {n}人がリノートしました
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4371539feb..978f4b6403 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2403,6 +2403,7 @@ _notification:
sendTestNotification: "テスト通知を送信する"
notificationWillBeDisplayedLikeThis: "通知はこのように表示されます"
reactedBySomeUsers: "{n}人がリアクションしました"
+ likedBySomeUsers: "{n}人がいいねしました"
renotedBySomeUsers: "{n}人がリノートしました"
followedBySomeUsers: "{n}人にフォローされました"
flushNotification: "通知の履歴をリセットする"
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index bf504378f8..75578750ce 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -2315,6 +2315,7 @@ _notification:
sendTestNotification: "테스트 알림 보내기"
notificationWillBeDisplayedLikeThis: "알림이 이렇게 표시됩니다"
reactedBySomeUsers: "{n}명이 반응했습니다"
+ likedBySomeUsers: "{n}명이 좋아요했습니다"
renotedBySomeUsers: "{n}명이 리노트했습니다"
followedBySomeUsers: "{n}명에게 팔로우됨"
_types:
diff --git a/packages/backend/src/@types/fastify.d.ts b/packages/backend/src/@types/fastify.d.ts
index b15176ec23..f63a90f948 100644
--- a/packages/backend/src/@types/fastify.d.ts
+++ b/packages/backend/src/@types/fastify.d.ts
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import FastifyReply from "fastify";
+import FastifyReply from 'fastify';
declare module 'fastify' {
interface FastifyReply {
diff --git a/packages/backend/src/core/UserAuthService.ts b/packages/backend/src/core/UserAuthService.ts
index 39eb771d6c..14f298c51f 100644
--- a/packages/backend/src/core/UserAuthService.ts
+++ b/packages/backend/src/core/UserAuthService.ts
@@ -8,7 +8,7 @@ import * as OTPAuth from 'otpauth';
import { DI } from '@/di-symbols.js';
import type { MiUserProfile, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
-import { IdentifiableError } from "@/misc/identifiable-error.js";
+import { IdentifiableError } from '@/misc/identifiable-error.js';
@Injectable()
export class UserAuthService {
diff --git a/packages/backend/src/core/entities/AnnouncementEntityService.ts b/packages/backend/src/core/entities/AnnouncementEntityService.ts
index 6a70aeece9..b4a67460d3 100644
--- a/packages/backend/src/core/entities/AnnouncementEntityService.ts
+++ b/packages/backend/src/core/entities/AnnouncementEntityService.ts
@@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import type { AnnouncementsRepository, AnnouncementReadsRepository, MiAnnouncement, MiUser } from "@/models/_.js";
+import type { AnnouncementsRepository, AnnouncementReadsRepository, MiAnnouncement, MiUser } from '@/models/_.js';
import type { Packed } from '@/misc/json-schema.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts
index 583d1282bb..6f8f5797a1 100644
--- a/packages/backend/src/core/entities/DriveFileEntityService.ts
+++ b/packages/backend/src/core/entities/DriveFileEntityService.ts
@@ -250,7 +250,7 @@ export class DriveFileEntityService {
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
detail: true,
}) : null,
- userId: opts.withUser ? file.userId : null,
+ userId: file.userId,
user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId, me) : null,
});
}
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 500d7741a7..f111b65402 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -338,6 +338,7 @@ export class NoteEntityService implements OnModuleInit {
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
renoteCount: note.renoteCount,
repliesCount: note.repliesCount,
+ reactionCount: Object.values(note.reactions).reduce((a, b) => a + b, 0),
reactions: this.reactionService.convertLegacyReactions(note.reactions),
reactionEmojis: this.customEmojiService.populateEmojis(reactionEmojiNames, host),
reactionAndUserPairCache: opts.withReactionAndUserPairCache ? note.reactionAndUserPairCache : undefined,
diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts
index bb4ccc7ee4..2641161c8b 100644
--- a/packages/backend/src/models/json-schema/note.ts
+++ b/packages/backend/src/models/json-schema/note.ts
@@ -223,6 +223,10 @@ export const packedNoteSchema = {
}],
},
},
+ reactionCount: {
+ type: 'number',
+ optional: false, nullable: false,
+ },
renoteCount: {
type: 'number',
optional: false, nullable: false,
diff --git a/packages/backend/src/queue/const.ts b/packages/backend/src/queue/const.ts
index 1d0caecf92..06edef1a20 100644
--- a/packages/backend/src/queue/const.ts
+++ b/packages/backend/src/queue/const.ts
@@ -4,7 +4,7 @@
*/
import type * as Bull from 'bullmq';
-import type { RedisOptions } from "ioredis";
+import type { RedisOptions } from 'ioredis';
import type { RedisOptionsSource } from '@/config.js';
export const QUEUE = {
diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
index 5583ab2053..3a6a70a1d0 100644
--- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
@@ -17,8 +17,8 @@ import { QueryService } from '@/core/QueryService.js';
import { MetaService } from '@/core/MetaService.js';
import { MiLocalUser } from '@/models/User.js';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
+import { FanoutTimelineName } from '@/core/FanoutTimelineService.js';
import { ApiError } from '../../error.js';
-import { FanoutTimelineName } from "@/core/FanoutTimelineService.js";
export const meta = {
tags: ['notes'],
diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts
index 917f5efa89..1013941724 100644
--- a/packages/backend/src/server/api/endpoints/users/reactions.ts
+++ b/packages/backend/src/server/api/endpoints/users/reactions.ts
@@ -12,8 +12,8 @@ import { DI } from '@/di-symbols.js';
import { CacheService } from '@/core/CacheService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { RoleService } from '@/core/RoleService.js';
+import { MiNoteReaction } from '@/models/_.js';
import { ApiError } from '../../error.js';
-import { MiNoteReaction } from "@/models/_.js";
export const meta = {
tags: ['users', 'reactions'],
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index f9dda1c31b..60f1e05e8a 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -72,8 +72,8 @@
//#endregion
//#region Script
- function importAppScript() {
- import(`/vite/${CLIENT_ENTRY}`)
+ async function importAppScript() {
+ await import(`/vite/${CLIENT_ENTRY}`)
.catch(async e => {
console.error(e);
renderError('APP_IMPORT', e);
diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts
index 4716454ef1..81da0fac31 100644
--- a/packages/backend/test/unit/AnnouncementService.ts
+++ b/packages/backend/test/unit/AnnouncementService.ts
@@ -10,7 +10,7 @@ import { ModuleMocker } from 'jest-mock';
import { Test } from '@nestjs/testing';
import { GlobalModule } from '@/GlobalModule.js';
import { AnnouncementService } from '@/core/AnnouncementService.js';
-import { AnnouncementEntityService } from "@/core/entities/AnnouncementEntityService.js";
+import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
import type {
AnnouncementReadsRepository,
AnnouncementsRepository,
diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue
index f2ed8e6647..cf44e10671 100644
--- a/packages/frontend/src/components/MkMediaAudio.vue
+++ b/packages/frontend/src/components/MkMediaAudio.vue
@@ -82,9 +82,7 @@ const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.data
const menuShowing = ref(false);
function showMenu(ev: MouseEvent) {
- let menu: MenuItem[] = [];
-
- menu = [
+ const menu: MenuItem[] = [
// TODO: 再生キューに追加
{
text: i18n.ts.hide,
@@ -95,15 +93,37 @@ function showMenu(ev: MouseEvent) {
},
];
- if (iAmModerator) {
+ if ($i?.id === props.audio.userId || iAmModerator) {
menu.push({
type: 'divider',
- }, {
+ });
+ }
+
+ if (iAmModerator) {
+ menu.push({
text: props.audio.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: props.audio.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
danger: true,
action: () => toggleSensitive(props.audio),
});
+
+ if ($i?.id !== props.audio.userId) {
+ menu.push({
+ type: 'link' as const,
+ text: i18n.ts._fileViewer.title,
+ icon: 'ti ti-info-circle',
+ to: `/admin/file/${props.audio.id}`,
+ });
+ }
+ }
+
+ if ($i?.id === props.audio.userId) {
+ menu.push({
+ type: 'link' as const,
+ text: i18n.ts._fileViewer.title,
+ icon: 'ti ti-info-circle',
+ to: `/my/drive/file/${props.audio.id}`,
+ });
}
menuShowing.value = true;
diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue
index 06217ae264..72ee04b5ac 100644
--- a/packages/frontend/src/components/MkMediaImage.vue
+++ b/packages/frontend/src/components/MkMediaImage.vue
@@ -53,6 +53,7 @@ SPDX-License-Identifier: AGPL-3.0-only