diff --git a/CHANGELOG.md b/CHANGELOG.md index af68dabcd6d216239d38cb83d12b18b236424ffc..87c9967c46675bed5b5b56a7fda3789bc6f29113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Feat: アンテナã§ãƒãƒ¼ã‚«ãƒ«ã®æŠ•ç¨¿ã®ã¿åŽé›†ã§ãるよã†ã«ãªã‚Šã¾ã—㟠- Feat: サーãƒãƒ¼ã‚µã‚¤ãƒ¬ãƒ³ã‚¹æ©Ÿèƒ½ãŒè¿½åŠ ã•ã‚Œã¾ã—㟠- Enhance: ä¾å˜é–¢ä¿‚ã®æ›´æ–° +- Enhance: æ–°è¦ã«ãƒ•ã‚©ãƒãƒ¼ã—ãŸäººã®ã‚’デフォルトã§TLã«è¿½åŠ ã§ãるよã†ã« ### Client - Enhance: TLã®è¿”信表示オプションを記憶ã™ã‚‹ã‚ˆã†ã« diff --git a/locales/index.d.ts b/locales/index.d.ts index 483c470be8ff173e733812f2d046cbeb9dd11437..363032eaa258134b14ba72a01c779f686d98fa32 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -537,6 +537,7 @@ export interface Locale { "deleteAll": string; "showFixedPostForm": string; "showFixedPostFormInChannel": string; + "withRepliesByDefaultForNewlyFollowed": string; "newNoteRecived": string; "sounds": string; "sound": string; @@ -2054,6 +2055,7 @@ export interface Locale { "userLists": string; "excludeMutingUsers": string; "excludeInactiveUsers": string; + "withReplies": string; }; "_charts": { "federation": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 725d1e7a87d3bd7ad9b8ade33203dca6467fe6df..bc539d17ddf8ec21136f5f45ea28afd79aa3fb3c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -534,6 +534,7 @@ serverLogs: "サーãƒãƒ¼ãƒã‚°" deleteAll: "å…¨ã¦å‰Šé™¤" showFixedPostForm: "タイムライン上部ã«æŠ•ç¨¿ãƒ•ã‚©ãƒ¼ãƒ を表示ã™ã‚‹" showFixedPostFormInChannel: "タイムライン上部ã«æŠ•ç¨¿ãƒ•ã‚©ãƒ¼ãƒ を表示ã™ã‚‹(ãƒãƒ£ãƒ³ãƒãƒ«)" +withRepliesByDefaultForNewlyFollowed: "フォãƒãƒ¼ã™ã‚‹éš›ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§è¿”ä¿¡ã‚’TLã«å«ã‚€ã‚ˆã†ã«ã™ã‚‹" newNoteRecived: "æ–°ã—ã„ノートãŒã‚ã‚Šã¾ã™" sounds: "サウンド" sound: "サウンド" @@ -1969,6 +1970,7 @@ _exportOrImport: userLists: "リスト" excludeMutingUsers: "ミュートã—ã¦ã„るユーザーを除外" excludeInactiveUsers: "使ã‚ã‚Œã¦ã„ãªã„アカウントを除外" + withReplies: "インãƒãƒ¼ãƒˆã—ãŸäººã«ã‚ˆã‚‹è¿”ä¿¡ã‚’TLã«å«ã‚€ã‚ˆã†ã«ã™ã‚‹" _charts: federation: "連åˆ" diff --git a/packages/backend/migration/1697441463087-FollowRequestWithReplies.js b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js new file mode 100644 index 0000000000000000000000000000000000000000..214c6f6680cf4f8cbfa94d6a25028cdfff9ecf9d --- /dev/null +++ b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + + +export class FollowRequestWithReplies1697441463087 { + name = 'FollowRequestWithReplies1697441463087' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "follow_request" ADD "withReplies" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "follow_request" DROP COLUMN "withReplies"`); + } +} diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index d8c725003496e53af425c10ad1eb0aeb4e14f1a1..be378a899b4e810addf1796e5afe70d6d3a743e7 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -237,10 +237,11 @@ export class QueueService { } @bindThis - public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id']) { + public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id'], withReplies?: boolean) { return this.dbQueue.add('importFollowing', { user: { id: user.id }, fileId: fileId, + withReplies, }, { removeOnComplete: true, removeOnFail: true, @@ -248,8 +249,8 @@ export class QueueService { } @bindThis - public createImportFollowingToDbJob(user: ThinUser, targets: string[]) { - const jobs = targets.map(rel => this.generateToDbJobData('importFollowingToDb', { user, target: rel })); + public createImportFollowingToDbJob(user: ThinUser, targets: string[], withReplies?: boolean) { + const jobs = targets.map(rel => this.generateToDbJobData('importFollowingToDb', { user, target: rel, withReplies })); return this.dbQueue.addBulk(jobs); } @@ -342,7 +343,7 @@ export class QueueService { } @bindThis - public createFollowJob(followings: { from: ThinUser, to: ThinUser, requestId?: string, silent?: boolean }[]) { + public createFollowJob(followings: { from: ThinUser, to: ThinUser, requestId?: string, silent?: boolean, withReplies?: boolean }[]) { const jobs = followings.map(rel => this.generateRelationshipJobData('follow', rel)); return this.relationshipQueue.addBulk(jobs); } @@ -384,6 +385,7 @@ export class QueueService { to: { id: data.to.id }, silent: data.silent, requestId: data.requestId, + withReplies: data.withReplies, }, opts: { removeOnComplete: true, diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 87484f03834b66453dbfd9aa781ad6d9c2fa4321..7548e3d28f1e1fde661ea83d66e9aaaf04a77d48 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -93,7 +93,15 @@ export class UserFollowingService implements OnModuleInit { } @bindThis - public async follow(_follower: { id: MiUser['id'] }, _followee: { id: MiUser['id'] }, requestId?: string, silent = false): Promise<void> { + public async follow( + _follower: { id: MiUser['id'] }, + _followee: { id: MiUser['id'] }, + { requestId, silent = false, withReplies }: { + requestId?: string, + silent?: boolean, + withReplies?: boolean, + } = {}, + ): Promise<void> { const [follower, followee] = await Promise.all([ this.usersRepository.findOneByOrFail({ id: _follower.id }), this.usersRepository.findOneByOrFail({ id: _followee.id }), @@ -171,12 +179,12 @@ export class UserFollowingService implements OnModuleInit { } if (!autoAccept) { - await this.createFollowRequest(follower, followee, requestId); + await this.createFollowRequest(follower, followee, requestId, withReplies); return; } } - await this.insertFollowingDoc(followee, follower, silent); + await this.insertFollowingDoc(followee, follower, silent, withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); @@ -193,6 +201,7 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'] }, silent = false, + withReplies?: boolean, ): Promise<void> { if (follower.id === followee.id) return; @@ -202,6 +211,7 @@ export class UserFollowingService implements OnModuleInit { id: this.idService.gen(), followerId: follower.id, followeeId: followee.id, + withReplies: withReplies, // éžæ£è¦åŒ– followerHost: follower.host, @@ -454,6 +464,7 @@ export class UserFollowingService implements OnModuleInit { id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']; }, requestId?: string, + withReplies?: boolean, ): Promise<void> { if (follower.id === followee.id) return; @@ -471,6 +482,7 @@ export class UserFollowingService implements OnModuleInit { followerId: follower.id, followeeId: followee.id, requestId, + withReplies, // éžæ£è¦åŒ– followerHost: follower.host, @@ -555,7 +567,7 @@ export class UserFollowingService implements OnModuleInit { throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No follow request.'); } - await this.insertFollowingDoc(followee, follower); + await this.insertFollowingDoc(followee, follower, false, request.withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee)); diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 8d5d34d40b0a1ebd9063ea87298858886277b17c..7aba140689510715a97f52d7ad94928eb8662492 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -164,7 +164,7 @@ export class ApInboxService { } // don't queue because the sender may attempt again when timeout - await this.userFollowingService.follow(actor, followee, activity.id); + await this.userFollowingService.follow(actor, followee, { requestId: activity.id }); return 'ok'; } diff --git a/packages/backend/src/models/FollowRequest.ts b/packages/backend/src/models/FollowRequest.ts index 1e907f3d68ef714ab341674958885233602a1648..9899694dd61db6b94951782bc4f99cc3b7cb7cbb 100644 --- a/packages/backend/src/models/FollowRequest.ts +++ b/packages/backend/src/models/FollowRequest.ts @@ -45,6 +45,11 @@ export class MiFollowRequest { }) public requestId: string | null; + @Column('boolean', { + default: false, + }) + public withReplies: boolean; + //#region Denormalized fields @Column('varchar', { length: 128, nullable: true, diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index 2b5e41a12de98bd6086fd696cc9caf41d927b970..e75499a56f84d0cdeb342c554ab2e90598b0f5cb 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -56,7 +56,7 @@ export class ImportFollowingProcessorService { const csv = await this.downloadService.downloadTextFile(file.url); const targets = csv.trim().split('\n'); - this.queueService.createImportFollowingToDbJob({ id: user.id }, targets); + this.queueService.createImportFollowingToDbJob({ id: user.id }, targets, job.data.withReplies); this.logger.succ('Import jobs created'); } @@ -93,9 +93,9 @@ export class ImportFollowingProcessorService { // skip myself if (target.id === job.data.user.id) return; - this.logger.info(`Follow ${target.id} ...`); + this.logger.info(`Follow ${target.id} ${job.data.withReplies ? 'with replies' : 'without replies'} ...`); - this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true }]); + this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: job.data.withReplies }]); } catch (e) { this.logger.warn(`Error: ${e}`); } diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index 5b2d2ef3139f6ee55ad7b46b745e03484a0b4ec9..b2d8e3631f3b03d5a68479fdf3547b4a48b17742 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -34,8 +34,12 @@ export class RelationshipProcessorService { @bindThis public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> { - this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id}`); - await this.userFollowingService.follow(job.data.from, job.data.to, job.data.requestId, job.data.silent); + this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? "with replies" : "without replies"}`); + await this.userFollowingService.follow(job.data.from, job.data.to, { + requestId: job.data.requestId, + silent: job.data.silent, + withReplies: job.data.withReplies, + }); return 'ok'; } diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index c9122f5ca2efb085d5e924d8e7a38c2b6c765a24..9330c01528f5adb7c09fe93cc3029685e3bae013 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -32,6 +32,7 @@ export type RelationshipJobData = { to: ThinUser; silent?: boolean; requestId?: string; + withReplies?: boolean; } export type DbJobData<T extends keyof DbJobMap> = DbJobMap[T]; @@ -79,6 +80,7 @@ export type DbUserDeleteJobData = { export type DbUserImportJobData = { user: ThinUser; fileId: MiDriveFile['id']; + withReplies?: boolean; }; export type DBAntennaImportJobData = { @@ -89,6 +91,7 @@ export type DBAntennaImportJobData = { export type DbUserImportToDbJobData = { user: ThinUser; target: string; + withReplies?: boolean; }; export type ObjectStorageJobData = ObjectStorageFileJobData | Record<string, unknown>; diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index e0e7fed87a23d6cd495accf5b9ca41a25ea466ff..9037944ef9efb364e144a23f2d1f0b6d6cc1778a 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -71,6 +71,7 @@ export const paramDef = { type: 'object', properties: { userId: { type: 'string', format: 'misskey:id' }, + withReplies: { type: 'boolean' } }, required: ['userId'], } as const; @@ -112,7 +113,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- } try { - await this.userFollowingService.follow(follower, followee); + await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies }); } catch (e) { if (e instanceof IdentifiableError) { if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index 38c9283043ab1c3f200c9dca0037b8ecc1e516db..e5fa2ac96a120f037b8cffbb56165eff44695e36 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -52,6 +52,7 @@ export const paramDef = { type: 'object', properties: { fileId: { type: 'string', format: 'misskey:id' }, + withReplies: { type: 'boolean' }, }, required: ['fileId'], } as const; @@ -79,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- ); if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile); - this.queueService.createImportFollowingJob(me, file.id); + this.queueService.createImportFollowingJob(me, file.id, ps.withReplies); }); } } diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index 15043fcd0b86659b25cd025808daa585fb55fe1c..b8de71e3b721894207ecf404b44b3b80f4987897 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -42,6 +42,7 @@ import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; import { claimAchievement } from '@/scripts/achievements.js'; import { $i } from '@/account.js'; +import { defaultStore } from "@/store.js"; const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed, @@ -52,6 +53,10 @@ const props = withDefaults(defineProps<{ large: false, }); +const emit = defineEmits<{ + (_: 'update:user', value: Misskey.entities.UserDetailed): void +}>(); + let isFollowing = $ref(props.user.isFollowing); let hasPendingFollowRequestFromYou = $ref(props.user.hasPendingFollowRequestFromYou); let wait = $ref(false); @@ -95,6 +100,11 @@ async function onClick() { } else { await os.api('following/create', { userId: props.user.id, + withReplies: defaultStore.state.defaultWithReplies, + }); + emit('update:user', { + ...props.user, + withReplies: defaultStore.state.defaultWithReplies }); hasPendingFollowRequestFromYou = true; diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index 33ef07d54b79ad99be1a204a2d62ae8e4553a063..bcba4196b55f8a340e100ec8b9a459d5ae291c63 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> <button class="_button" :class="$style.menu" @click="showMenu"><i class="ti ti-dots"></i></button> - <MkFollowButton v-if="$i && user.id != $i.id" :class="$style.follow" :user="user" mini/> + <MkFollowButton v-if="$i && user.id != $i.id" v-model:user="user" :class="$style.follow" mini/> </div> <div v-else> <MkLoading/> diff --git a/packages/frontend/src/pages/follow.vue b/packages/frontend/src/pages/follow.vue index e382cabd748008ebeb375fa5eaf105329d7b0bc2..a0a4a480b577d9ef48a55941433af5fc164a992d 100644 --- a/packages/frontend/src/pages/follow.vue +++ b/packages/frontend/src/pages/follow.vue @@ -14,6 +14,7 @@ import * as Misskey from 'misskey-js'; import * as os from '@/os.js'; import { mainRouter } from '@/router.js'; import { i18n } from '@/i18n.js'; +import { defaultStore } from "@/store.js"; async function follow(user): Promise<void> { const { canceled } = await os.confirm({ @@ -28,7 +29,9 @@ async function follow(user): Promise<void> { os.apiWithDialog('following/create', { userId: user.id, + withReplies: defaultStore.state.defaultWithReplies, }); + user.withReplies = defaultStore.state.defaultWithReplies; } const acct = new URL(location.href).searchParams.get('acct'); diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue index 3f4f657e94727abd8abd67e1e7ffa436ff59055d..3863348eaef56f4cb06b42f08535717690464332 100644 --- a/packages/frontend/src/pages/gallery/post.vue +++ b/packages/frontend/src/pages/gallery/post.vue @@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkUserName :user="post.user" style="display: block;"/> <MkAcct :user="post.user"/> </div> - <MkFollowButton v-if="!$i || $i.id != post.user.id" :user="post.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/> + <MkFollowButton v-if="!$i || $i.id != post.user.id" v-model:user="post.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/> </div> </div> <MkAd :prefer="['horizontal', 'horizontal-big']"/> diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 55de53fb07857713b488f12402f6d422e35e8112..30443fded6c01cc83aa7fafb1c222b491085e674 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -29,6 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_s"> <MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch> <MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch> + <MkSwitch v-model="defaultWithReplies">{{ i18n.ts.withRepliesByDefaultForNewlyFollowed }}</MkSwitch> <MkFolder> <template #label>{{ i18n.ts.pinnedList }}</template> <!-- 複数ピンæ¢ã‚管ç†ã§ãるよã†ã«ã—ãŸã„ã‘ã©ã‚ã‚“ã©ã„ã®ã§ä¸€æ—¦ã²ã¨ã¤ã®ã¿ --> @@ -249,6 +250,7 @@ const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter(' const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn')); +const defaultWithReplies = computed(defaultStore.makeGetterSetter('defaultWithReplies')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); diff --git a/packages/frontend/src/pages/settings/import-export.vue b/packages/frontend/src/pages/settings/import-export.vue index 0574a878aee5a84593ff378ca48053e7689f4924..0f01fda26f036ef819510fd67fe9ed6d690854d4 100644 --- a/packages/frontend/src/pages/settings/import-export.vue +++ b/packages/frontend/src/pages/settings/import-export.vue @@ -40,6 +40,9 @@ SPDX-License-Identifier: AGPL-3.0-only <MkFolder v-if="$i && !$i.movedTo"> <template #label>{{ i18n.ts.import }}</template> <template #icon><i class="ti ti-upload"></i></template> + <MkSwitch v-model="withReplies"> + {{ i18n.ts._exportOrImport.withReplies }} + </MkSwitch> <MkButton primary :class="$style.button" inline @click="importFollowing($event)"><i class="ti ti-upload"></i> {{ i18n.ts.import }}</MkButton> </MkFolder> </div> @@ -118,9 +121,11 @@ import { selectFile } from '@/scripts/select-file.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { $i } from '@/account.js'; +import { defaultStore } from "@/store.js"; const excludeMutingUsers = ref(false); const excludeInactiveUsers = ref(false); +const withReplies = ref(defaultStore.state.defaultWithReplies); const onExportSuccess = () => { os.alert({ @@ -177,7 +182,10 @@ const exportAntennas = () => { const importFollowing = async (ev) => { const file = await selectFile(ev.currentTarget ?? ev.target); - os.api('i/import-following', { fileId: file.id }).then(onImportSuccess).catch(onError); + os.api('i/import-following', { + fileId: file.id, + withReplies: withReplies.value, + }).then(onImportSuccess).catch(onError); }; const importUserLists = async (ev) => { diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 605e9fbb76390c904c1668a5c36e558ebb1bfc2d..4c425898d5d3f9f5ff69f86af101079a8cb42352 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only <span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ i18n.ts.followsYou }}</span> <div v-if="$i" class="actions"> <button class="menu _button" @click="menu"><i class="ti ti-dots"></i></button> - <MkFollowButton v-if="$i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/> + <MkFollowButton v-if="$i.id != user.id" v-model:user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/> </div> </div> <MkAvatar class="avatar" :user="user" indicator/> @@ -198,6 +198,7 @@ const props = withDefaults(defineProps<{ const router = useRouter(); +let user = $ref(props.user); let parallaxAnimationId = $ref<null | number>(null); let narrow = $ref<null | boolean>(null); let rootEl = $ref<null | HTMLElement>(null); @@ -232,7 +233,7 @@ const age = $computed(() => { }); function menu(ev) { - const { menu, cleanup } = getUserMenu(props.user, router); + const { menu, cleanup } = getUserMenu(user, router); os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup); } diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 2829411ae58546438ffb6b9751da290ba78df981..92d01e4caf1359a543fa5fce387aca8b3b57b14a 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -361,6 +361,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, + defaultWithReplies: { + where: 'account', + default: false, + }, })); // TODO: ä»–ã®ã‚¿ãƒ–ã¨æ°¸ç¶šåŒ–ã•ã‚ŒãŸstateã‚’åŒæœŸ diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 6b01321047239b8c5ed0fbbecb2c148f08a2af51..895f34689b100e0861f40c23638483640de25930 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1185,6 +1185,7 @@ export type Endpoints = { 'following/create': { req: { userId: User['id']; + withReplies?: boolean; }; res: User; }; @@ -2985,7 +2986,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:603:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index a7a2ea1b36ee75cd75a0caef39dde87bd63a7e1c..8c6205bf51286e688506fe9e8bcc2a359b45d556 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -321,7 +321,10 @@ export type Endpoints = { 'federation/users': { req: { host: string; limit?: number; sinceId?: User['id']; untilId?: User['id']; }; res: UserDetailed[]; }; // following - 'following/create': { req: { userId: User['id'] }; res: User; }; + 'following/create': { req: { + userId: User['id'], + withReplies?: boolean, + }; res: User; }; 'following/delete': { req: { userId: User['id'] }; res: User; }; 'following/requests/accept': { req: { userId: User['id'] }; res: null; }; 'following/requests/cancel': { req: { userId: User['id'] }; res: User; };