diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cceb6e432..770b37a206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,8 @@ - Fix: 複数のメンションを1行に記述した場合に、サジェストが正しく表示されない問題を修正 - Fix: メンションとしての条件を満たしていても、特定の条件(`-`が含まれる場合など)で正しくサジェストされない問題を一部修正 - Fix: ユーザーの前後ノートを閲覧する機能が動作しない問題を修正 +- Fix: 照会ダイアログでap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正 +- Fix: アイコンのデコレーションを付ける際にデコレーションが表示されなくなる問題を修正 ### Server - Feat: サーバー管理コマンド diff --git a/packages/backend/src/core/entities/NoteReactionEntityService.ts b/packages/backend/src/core/entities/NoteReactionEntityService.ts index 46ec13704c..54ce4d472a 100644 --- a/packages/backend/src/core/entities/NoteReactionEntityService.ts +++ b/packages/backend/src/core/entities/NoteReactionEntityService.ts @@ -49,15 +49,12 @@ export class NoteReactionEntityService implements OnModuleInit { public async pack( src: MiNoteReaction['id'] | MiNoteReaction, me?: { id: MiUser['id'] } | null | undefined, - options?: { - withNote: boolean; - }, + options?: object, hints?: { packedUser?: Packed<'UserLite'> }, ): Promise> { const opts = Object.assign({ - withNote: false, }, options); const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src }); @@ -67,9 +64,6 @@ export class NoteReactionEntityService implements OnModuleInit { createdAt: this.idService.parse(reaction.id).date.toISOString(), user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me), type: this.reactionService.convertLegacyReaction(reaction.reaction), - ...(opts.withNote ? { - note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me), - } : {}), }; } @@ -77,16 +71,50 @@ export class NoteReactionEntityService implements OnModuleInit { public async packMany( reactions: MiNoteReaction[], me?: { id: MiUser['id'] } | null | undefined, - options?: { - withNote: boolean; - }, + options?: object, ): Promise[]> { const opts = Object.assign({ - withNote: false, }, options); const _users = reactions.map(({ user, userId }) => user ?? userId); const _userMap = await this.userEntityService.packMany(_users, me) .then(users => new Map(users.map(u => [u.id, u]))); return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) }))); } + + @bindThis + public async packWithNote( + src: MiNoteReaction['id'] | MiNoteReaction, + me?: { id: MiUser['id'] } | null | undefined, + options?: object, + hints?: { + packedUser?: Packed<'UserLite'> + }, + ): Promise> { + const opts = Object.assign({ + }, options); + + const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src }); + + return { + id: reaction.id, + createdAt: this.idService.parse(reaction.id).date.toISOString(), + user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me), + type: this.reactionService.convertLegacyReaction(reaction.reaction), + note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me), + }; + } + + @bindThis + public async packManyWithNote( + reactions: MiNoteReaction[], + me?: { id: MiUser['id'] } | null | undefined, + options?: object, + ): Promise[]> { + const opts = Object.assign({ + }, options); + const _users = reactions.map(({ user, userId }) => user ?? userId); + const _userMap = await this.userEntityService.packMany(_users, me) + .then(users => new Map(users.map(u => [u.id, u]))); + return Promise.all(reactions.map(reaction => this.packWithNote(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) }))); + } } diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index ed47edff9b..dca92e1037 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -22,7 +22,7 @@ import { packedFollowingSchema } from '@/models/json-schema/following.js'; import { packedMutingSchema } from '@/models/json-schema/muting.js'; import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js'; import { packedBlockingSchema } from '@/models/json-schema/blocking.js'; -import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js'; +import { packedNoteReactionSchema, packedNoteReactionWithNoteSchema } from '@/models/json-schema/note-reaction.js'; import { packedHashtagSchema } from '@/models/json-schema/hashtag.js'; import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js'; import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js'; @@ -92,6 +92,7 @@ export const refs = { Note: packedNoteSchema, NoteDraft: packedNoteDraftSchema, NoteReaction: packedNoteReactionSchema, + NoteReactionWithNote: packedNoteReactionWithNoteSchema, NoteFavorite: packedNoteFavoriteSchema, Notification: packedNotificationSchema, DriveFile: packedDriveFileSchema, diff --git a/packages/backend/src/models/json-schema/note-reaction.ts b/packages/backend/src/models/json-schema/note-reaction.ts index 95658ace1f..04c9f34232 100644 --- a/packages/backend/src/models/json-schema/note-reaction.ts +++ b/packages/backend/src/models/json-schema/note-reaction.ts @@ -10,7 +10,6 @@ export const packedNoteReactionSchema = { type: 'string', optional: false, nullable: false, format: 'id', - example: 'xxxxxxxxxx', }, createdAt: { type: 'string', @@ -28,3 +27,33 @@ export const packedNoteReactionSchema = { }, }, } as const; + +export const packedNoteReactionWithNoteSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + createdAt: { + type: 'string', + optional: false, nullable: false, + format: 'date-time', + }, + user: { + type: 'object', + optional: false, nullable: false, + ref: 'UserLite', + }, + type: { + type: 'string', + optional: false, nullable: false, + }, + note: { + type: 'object', + optional: false, nullable: false, + ref: 'Note', + }, + }, +} as const; diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 81a788de2b..804bd5d9b9 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -49,6 +49,34 @@ export const meta = { type: 'string', optional: false, nullable: false, }, + icon: { + type: 'string', + optional: false, nullable: true, + }, + display: { + type: 'string', + optional: false, nullable: false, + }, + isActive: { + type: 'boolean', + optional: false, nullable: false, + }, + forExistingUsers: { + type: 'boolean', + optional: false, nullable: false, + }, + silence: { + type: 'boolean', + optional: false, nullable: false, + }, + needConfirmationToRead: { + type: 'boolean', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: true, + }, imageUrl: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index 8756801fe4..ed5952d4c5 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -23,6 +23,16 @@ export const meta = { type: 'object', optional: false, nullable: false, ref: 'UserList', + properties: { + likedCount: { + type: 'number', + optional: true, nullable: false, + }, + isLiked: { + type: 'boolean', + optional: true, nullable: false, + }, + }, }, errors: { diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index d6f1ecd8ed..d84a191f7a 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -28,7 +28,7 @@ export const meta = { items: { type: 'object', optional: false, nullable: false, - ref: 'NoteReaction', + ref: 'NoteReactionWithNote', }, }, @@ -120,7 +120,7 @@ export default class extends Endpoint { // eslint- return true; }); - return await this.noteReactionEntityService.packMany(reactions, me, { withNote: true }); + return await this.noteReactionEntityService.packManyWithNote(reactions, me); }); } } diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 6ae8379801..18817d3f79 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -368,11 +368,6 @@ export async function mainBoot() { }); }); - main.on('unreadAntenna', () => { - updateCurrentAccountPartial({ hasUnreadAntenna: true }); - sound.playMisskeySfx('antenna'); - }); - main.on('newChatMessage', () => { updateCurrentAccountPartial({ hasUnreadChatMessages: true }); sound.playMisskeySfx('chatMessage'); diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue index 70766634ce..bf39c1e983 100644 --- a/packages/frontend/src/components/MkAchievements.vue +++ b/packages/frontend/src/components/MkAchievements.vue @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only [$style.iconFrame_platinum]: ACHIEVEMENT_BADGES[achievement.name].frame === 'platinum', }]" > -
+
@@ -71,7 +71,7 @@ const props = withDefaults(defineProps<{ const achievements = ref(null); const lockedAchievements = computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements.value ?? []).some(a => a.name === x))); -function fetch() { +function _fetch_() { misskeyApi('users/achievements', { userId: props.user.id }).then(res => { achievements.value = []; for (const t of ACHIEVEMENT_TYPES) { @@ -84,11 +84,11 @@ function fetch() { function clickHere() { claimAchievement('clickedClickHere'); - fetch(); + _fetch_(); } onMounted(() => { - fetch(); + _fetch_(); }); diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index 82606c9aa4..19a21f6e24 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -265,6 +265,8 @@ onUnmounted(() => { if (handle) { window.cancelAnimationFrame(handle); } + + // TODO: WebGLリソースの解放 }); diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue index 4d67bba70d..c54081ad42 100644 --- a/packages/frontend/src/components/MkChart.vue +++ b/packages/frontend/src/components/MkChart.vue @@ -589,7 +589,10 @@ const fetchDriveFilesChart = async (): Promise => { }; const fetchInstanceRequestsChart = async (): Promise => { - const raw = await misskeyApiGet('charts/instance', { host: props.args?.host, limit: props.limit, span: props.span }); + const host = props.args?.host; + if (host == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/instance', { host: host, limit: props.limit, span: props.span }); return { series: [{ name: 'In', @@ -611,7 +614,10 @@ const fetchInstanceRequestsChart = async (): Promise => { }; const fetchInstanceUsersChart = async (total: boolean): Promise => { - const raw = await misskeyApiGet('charts/instance', { host: props.args?.host, limit: props.limit, span: props.span }); + const host = props.args?.host; + if (host == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/instance', { host: host, limit: props.limit, span: props.span }); return { series: [{ name: 'Users', @@ -626,7 +632,10 @@ const fetchInstanceUsersChart = async (total: boolean): Promise => { - const raw = await misskeyApiGet('charts/instance', { host: props.args?.host, limit: props.limit, span: props.span }); + const host = props.args?.host; + if (host == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/instance', { host: host, limit: props.limit, span: props.span }); return { series: [{ name: 'Notes', @@ -641,7 +650,10 @@ const fetchInstanceNotesChart = async (total: boolean): Promise => { - const raw = await misskeyApiGet('charts/instance', { host: props.args?.host, limit: props.limit, span: props.span }); + const host = props.args?.host; + if (host == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/instance', { host: host, limit: props.limit, span: props.span }); return { series: [{ name: 'Following', @@ -664,7 +676,10 @@ const fetchInstanceFfChart = async (total: boolean): Promise = }; const fetchInstanceDriveUsageChart = async (total: boolean): Promise => { - const raw = await misskeyApiGet('charts/instance', { host: props.args?.host, limit: props.limit, span: props.span }); + const host = props.args?.host; + if (host == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/instance', { host: host, limit: props.limit, span: props.span }); return { bytes: true, series: [{ @@ -680,7 +695,10 @@ const fetchInstanceDriveUsageChart = async (total: boolean): Promise => { - const raw = await misskeyApiGet('charts/instance', { host: props.args?.host, limit: props.limit, span: props.span }); + const host = props.args?.host; + if (host == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/instance', { host: host, limit: props.limit, span: props.span }); return { series: [{ name: 'Drive files', @@ -695,7 +713,10 @@ const fetchInstanceDriveFilesChart = async (total: boolean): Promise => { - const raw = await misskeyApiGet('charts/user/notes', { userId: props.args?.user?.id, limit: props.limit, span: props.span }); + const userId = props.args?.user?.id; + if (userId == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/user/notes', { userId: userId, limit: props.limit, span: props.span }); return { series: [...(props.args?.withoutAll ? [] : [{ name: 'All', @@ -727,7 +748,10 @@ const fetchPerUserNotesChart = async (): Promise => { }; const fetchPerUserPvChart = async (): Promise => { - const raw = await misskeyApiGet('charts/user/pv', { userId: props.args?.user?.id, limit: props.limit, span: props.span }); + const userId = props.args?.user?.id; + if (userId == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/user/pv', { userId: userId, limit: props.limit, span: props.span }); return { series: [{ name: 'Unique PV (user)', @@ -754,7 +778,10 @@ const fetchPerUserPvChart = async (): Promise => { }; const fetchPerUserFollowingChart = async (): Promise => { - const raw = await misskeyApiGet('charts/user/following', { userId: props.args?.user?.id, limit: props.limit, span: props.span }); + const userId = props.args?.user?.id; + if (userId == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/user/following', { userId: userId, limit: props.limit, span: props.span }); return { series: [{ name: 'Local', @@ -769,7 +796,10 @@ const fetchPerUserFollowingChart = async (): Promise => { }; const fetchPerUserFollowersChart = async (): Promise => { - const raw = await misskeyApiGet('charts/user/following', { userId: props.args?.user?.id, limit: props.limit, span: props.span }); + const userId = props.args?.user?.id; + if (userId == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/user/following', { userId: userId, limit: props.limit, span: props.span }); return { series: [{ name: 'Local', @@ -784,7 +814,10 @@ const fetchPerUserFollowersChart = async (): Promise => { }; const fetchPerUserDriveChart = async (): Promise => { - const raw = await misskeyApiGet('charts/user/drive', { userId: props.args?.user?.id, limit: props.limit, span: props.span }); + const userId = props.args?.user?.id; + if (userId == null) return { series: [] }; + + const raw = await misskeyApiGet('charts/user/drive', { userId: userId, limit: props.limit, span: props.span }); return { bytes: true, series: [{ diff --git a/packages/frontend/src/components/MkCropperDialog.vue b/packages/frontend/src/components/MkCropperDialog.vue index 7f592fba79..6c07eac47a 100644 --- a/packages/frontend/src/components/MkCropperDialog.vue +++ b/packages/frontend/src/components/MkCropperDialog.vue @@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index bf0e5e1b37..6ba3af72b9 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -9,7 +9,7 @@ import { markRaw, ref, defineAsyncComponent, nextTick } from 'vue'; import { EventEmitter } from 'eventemitter3'; import * as Misskey from 'misskey-js'; import type { Component, Ref } from 'vue'; -import type { ComponentProps as CP } from 'vue-component-type-helpers'; +import type { ComponentEmit, ComponentProps as CP } from 'vue-component-type-helpers'; import type { Form, GetFormResultType } from '@/utility/form.js'; import type { MenuItem } from '@/types/menu.js'; import type { PostFormProps } from '@/types/post-form.js'; @@ -157,28 +157,9 @@ export function claimZIndex(priority: keyof typeof zIndexes = 'low'): number { return zIndexes[priority]; } -// InstanceType['$emit'] だとインターセクション型が返ってきて -// 使い物にならないので、代わりに ['$props'] から色々省くことで emit の型を生成する -// FIXME: 何故か *.ts ファイルからだと型がうまく取れない?ことがあるのをなんとかしたい -type ComponentEmit = T extends new () => { $props: infer Props } - ? [keyof Pick>] extends [never] - ? Record // *.ts ファイルから型がうまく取れないとき用(これがないと {} になって型エラーがうるさい) - : EmitsExtractor - : T extends (...args: any) => any - ? ReturnType extends { [x: string]: any; __ctx?: { [x: string]: any; props: infer Props } } - ? [keyof Pick>] extends [never] - ? Record - : EmitsExtractor - : never - : never; - // props に ref を許可するようにする type ComponentProps = { [K in keyof CP]: CP[K] | Ref[K]> }; -type EmitsExtractor = { - [K in keyof T as K extends `onVnode${string}` ? never : K extends `on${infer E}` ? Uncapitalize : K extends string ? never : K]: T[K]; -}; - export function popup( component: T, props: ComponentProps, diff --git a/packages/frontend/src/pages/admin-file.vue b/packages/frontend/src/pages/admin-file.vue index 7a49ba542f..90b3ca81cf 100644 --- a/packages/frontend/src/pages/admin-file.vue +++ b/packages/frontend/src/pages/admin-file.vue @@ -111,13 +111,13 @@ const props = defineProps<{ fileId: string, }>(); -async function fetch() { +async function _fetch_() { file.value = await misskeyApi('drive/files/show', { fileId: props.fileId }); info.value = await misskeyApi('admin/drive/show-file', { fileId: props.fileId }); isSensitive.value = file.value.isSensitive; } -fetch(); +_fetch_(); async function del() { const { canceled } = await os.confirm({ diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 437bf22363..38e3c7a11b 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -143,8 +143,8 @@ SPDX-License-Identifier: AGPL-3.0-only
-
Assigned:
-
Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id).expiresAt).toLocaleString() }}
+
Assigned:
+
Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id)!.expiresAt!).toLocaleString() }}
Period: {{ i18n.ts.indefinitely }}
diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index c5baeda7b0..06a28db088 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -140,15 +140,15 @@ function toggleDayOfWeek(ad, index) { function add() { ads.value.unshift({ - id: null, + id: '', memo: '', place: 'square', priority: 'middle', ratio: 1, url: '', - imageUrl: null, - expiresAt: null, - startsAt: null, + imageUrl: '', + expiresAt: new Date().toISOString(), + startsAt: new Date().toISOString(), dayOfWeek: 0, }); } @@ -160,7 +160,7 @@ function remove(ad) { }).then(({ canceled }) => { if (canceled) return; ads.value = ads.value.filter(x => x !== ad); - if (ad.id == null) return; + if (ad.id === '') return; os.apiWithDialog('admin/ad/delete', { id: ad.id, }).then(() => { @@ -170,7 +170,7 @@ function remove(ad) { } function save(ad) { - if (ad.id == null) { + if (ad.id === '') { misskeyApi('admin/ad/create', { ...ad, expiresAt: new Date(ad.expiresAt).getTime(), @@ -207,7 +207,7 @@ function save(ad) { } function more() { - misskeyApi('admin/ad/list', { untilId: ads.value.reduce((acc, ad) => ad.id != null ? ad : acc).id, publishing: publishing }).then(adsResponse => { + misskeyApi('admin/ad/list', { untilId: ads.value.reduce((acc, ad) => ad.id !== '' ? ad : acc).id, publishing: publishing }).then(adsResponse => { if (adsResponse == null) return; ads.value = ads.value.concat(adsResponse.map(r => { const exdate = new Date(r.expiresAt); diff --git a/packages/frontend/src/pages/announcement.vue b/packages/frontend/src/pages/announcement.vue index f9b870eda1..0bcfd28f67 100644 --- a/packages/frontend/src/pages/announcement.vue +++ b/packages/frontend/src/pages/announcement.vue @@ -39,7 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.gotIt }} - + @@ -66,7 +66,7 @@ const announcement = ref(null); const error = ref(null); const path = computed(() => props.announcementId); -function fetch() { +function _fetch_() { announcement.value = null; misskeyApi('announcements/show', { announcementId: props.announcementId, @@ -96,7 +96,7 @@ async function read(target: Misskey.entities.Announcement): Promise { } } -watch(() => path.value, fetch, { immediate: true }); +watch(() => path.value, _fetch_, { immediate: true }); const headerActions = computed(() => []); diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue index ede0f268ee..7e13d0ab36 100644 --- a/packages/frontend/src/pages/auth.vue +++ b/packages/frontend/src/pages/auth.vue @@ -75,14 +75,15 @@ onMounted(async () => { if (!$i) return; try { - session.value = await misskeyApi('auth/session/show', { + const result = await misskeyApi('auth/session/show', { token: props.token, }); + session.value = result; // 既に連携していた場合 - if (session.value.app.isAuthorized) { + if (result.app.isAuthorized) { await misskeyApi('auth/accept', { - token: session.value.token, + token: result.token, }); accepted(); } else { diff --git a/packages/frontend/src/pages/channel-editor.vue b/packages/frontend/src/pages/channel-editor.vue index 80dfb8e84e..ce26a26109 100644 --- a/packages/frontend/src/pages/channel-editor.vue +++ b/packages/frontend/src/pages/channel-editor.vue @@ -92,7 +92,7 @@ const props = defineProps<{ }>(); const channel = ref(null); -const name = ref(null); +const name = ref(''); const description = ref(null); const bannerUrl = ref(null); const bannerId = ref(null); @@ -114,20 +114,22 @@ watch(() => bannerId.value, async () => { async function fetchChannel() { if (props.channelId == null) return; - channel.value = await misskeyApi('channels/show', { + const result = await misskeyApi('channels/show', { channelId: props.channelId, }); - name.value = channel.value.name; - description.value = channel.value.description; - bannerId.value = channel.value.bannerId; - bannerUrl.value = channel.value.bannerUrl; - isSensitive.value = channel.value.isSensitive; - pinnedNotes.value = channel.value.pinnedNoteIds.map(id => ({ + name.value = result.name; + description.value = result.description; + bannerId.value = result.bannerId; + bannerUrl.value = result.bannerUrl; + isSensitive.value = result.isSensitive; + pinnedNotes.value = result.pinnedNoteIds.map(id => ({ id, })); - color.value = channel.value.color; - allowRenoteToExternal.value = channel.value.allowRenoteToExternal; + color.value = result.color; + allowRenoteToExternal.value = result.allowRenoteToExternal; + + channel.value = result; } fetchChannel(); @@ -154,15 +156,17 @@ function save() { name: name.value, description: description.value, bannerId: bannerId.value, - pinnedNoteIds: pinnedNotes.value.map(x => x.id), color: color.value, isSensitive: isSensitive.value, allowRenoteToExternal: allowRenoteToExternal.value, - }; + } satisfies Misskey.entities.ChannelsCreateRequest; - if (props.channelId) { - params.channelId = props.channelId; - os.apiWithDialog('channels/update', params); + if (props.channelId != null) { + os.apiWithDialog('channels/update', { + ...params, + channelId: props.channelId, + pinnedNoteIds: pinnedNotes.value.map(x => x.id), + }); } else { os.apiWithDialog('channels/create', params).then(created => { router.push('/channels/:channelId', { @@ -175,12 +179,13 @@ function save() { } async function archive() { + if (props.channelId == null) return; + const { canceled } = await os.confirm({ type: 'warning', title: i18n.tsx.channelArchiveConfirmTitle({ name: name.value }), text: i18n.ts.channelArchiveConfirmDescription, }); - if (canceled) return; misskeyApi('channels/update', { diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue index 1cb07017e9..0f306896c9 100644 --- a/packages/frontend/src/pages/custom-emojis-manager.vue +++ b/packages/frontend/src/pages/custom-emojis-manager.vue @@ -312,6 +312,7 @@ const headerActions = computed(() => [{ handler: add, }, { icon: 'ti ti-dots', + text: i18n.ts.more, handler: menu, }]); diff --git a/packages/frontend/src/pages/drive.file.info.vue b/packages/frontend/src/pages/drive.file.info.vue index 1def215afc..e3cc1d988e 100644 --- a/packages/frontend/src/pages/drive.file.info.vue +++ b/packages/frontend/src/pages/drive.file.info.vue @@ -105,7 +105,7 @@ const folderHierarchy = computed(() => { }); const isImage = computed(() => file.value?.type.startsWith('image/')); -async function fetch() { +async function _fetch_() { fetching.value = true; file.value = await misskeyApi('drive/files/show', { @@ -119,7 +119,7 @@ async function fetch() { } function postThis() { - if (!file.value) return; + if (file.value == null) return; os.post({ initialFiles: [file.value], @@ -127,26 +127,28 @@ function postThis() { } function move() { - if (!file.value) return; + if (file.value == null) return; + + const f = file.value; selectDriveFolder(null).then(folder => { misskeyApi('drive/files/update', { - fileId: file.value.id, + fileId: f.id, folderId: folder[0] ? folder[0].id : null, }).then(async () => { - await fetch(); + await _fetch_(); }); }); } function toggleSensitive() { - if (!file.value) return; + if (file.value == null) return; os.apiWithDialog('drive/files/update', { fileId: file.value.id, isSensitive: !file.value.isSensitive, }).then(async () => { - await fetch(); + await _fetch_(); }).catch(err => { os.alert({ type: 'error', @@ -157,7 +159,9 @@ function toggleSensitive() { } function rename() { - if (!file.value) return; + if (file.value == null) return; + + const f = file.value; os.inputText({ title: i18n.ts.renameFile, @@ -166,16 +170,18 @@ function rename() { }).then(({ canceled, result: name }) => { if (canceled) return; os.apiWithDialog('drive/files/update', { - fileId: file.value.id, + fileId: f.id, name: name, }).then(async () => { - await fetch(); + await _fetch_(); }); }); } async function describe() { - if (!file.value) return; + if (file.value == null) return; + + const f = file.value; const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkFileCaptionEditWindow.vue').then(x => x.default), { default: file.value.comment ?? '', @@ -183,10 +189,10 @@ async function describe() { }, { done: caption => { os.apiWithDialog('drive/files/update', { - fileId: file.value.id, + fileId: f.id, comment: caption.length === 0 ? null : caption, }).then(async () => { - await fetch(); + await _fetch_(); }); }, closed: () => dispose(), @@ -194,7 +200,7 @@ async function describe() { } async function deleteFile() { - if (!file.value) return; + if (file.value == null) return; const { canceled } = await os.confirm({ type: 'warning', @@ -212,7 +218,7 @@ async function deleteFile() { } onMounted(async () => { - await fetch(); + await _fetch_(); }); diff --git a/packages/frontend/src/pages/explore.vue b/packages/frontend/src/pages/explore.vue index c4f6ddc33e..6416816e6c 100644 --- a/packages/frontend/src/pages/explore.vue +++ b/packages/frontend/src/pages/explore.vue @@ -26,18 +26,12 @@ import { definePage } from '@/page.js'; import { i18n } from '@/i18n.js'; const props = withDefaults(defineProps<{ - tag?: string; initialTab?: string; }>(), { initialTab: 'featured', }); const tab = ref(props.initialTab); -const tagsEl = useTemplateRef('tagsEl'); - -watch(() => props.tag, () => { - if (tagsEl.value) tagsEl.value.toggleContent(props.tag == null); -}); const headerActions = computed(() => []); diff --git a/packages/frontend/src/pages/gallery/edit.vue b/packages/frontend/src/pages/gallery/edit.vue index cf0d700962..3fd462e0b9 100644 --- a/packages/frontend/src/pages/gallery/edit.vue +++ b/packages/frontend/src/pages/gallery/edit.vue @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
{{ file.name }}
@@ -88,7 +88,7 @@ async function save() { router.push('/gallery/:postId', { params: { postId: props.postId, - } + }, }); } else { const created = await os.apiWithDialog('gallery/posts/create', { @@ -100,7 +100,7 @@ async function save() { router.push('/gallery/:postId', { params: { postId: created.id, - } + }, }); } } diff --git a/packages/frontend/src/pages/install-extensions.vue b/packages/frontend/src/pages/install-extensions.vue index 1b3c6616cc..cad3b2a00a 100644 --- a/packages/frontend/src/pages/install-extensions.vue +++ b/packages/frontend/src/pages/install-extensions.vue @@ -80,7 +80,7 @@ function close_(): void { } } -async function fetch() { +async function _fetch_() { if (!url.value || !hash.value) { errorKV.value = { title: i18n.ts._externalResourceInstaller._errors._invalidParams.title, @@ -161,7 +161,7 @@ async function fetch() { }, raw: res.data, }; - } catch (err) { + } catch (err: any) { switch (err.message.toLowerCase()) { case 'this theme is already installed': errorKV.value = { @@ -229,7 +229,7 @@ async function install() { const urlParams = new URLSearchParams(window.location.search); url.value = urlParams.get('url'); hash.value = urlParams.get('hash'); -fetch(); +_fetch_(); definePage(() => ({ title: i18n.ts._externalResourceInstaller.title, diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index 4be5fa447d..473207fe6e 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -198,7 +198,7 @@ if (iAmModerator) { }); } -async function fetch(): Promise { +async function _fetch_(): Promise { if (iAmAdmin) { meta.value = await misskeyApi('admin/meta'); } @@ -276,7 +276,7 @@ function refreshMetadata(): void { }); } -fetch(); +_fetch_(); const headerActions = computed(() => [{ text: `https://${props.host}`, diff --git a/packages/frontend/src/pages/list.vue b/packages/frontend/src/pages/list.vue index 1261428c1c..a52b562c7f 100644 --- a/packages/frontend/src/pages/list.vue +++ b/packages/frontend/src/pages/list.vue @@ -103,6 +103,7 @@ definePage(() => ({ icon: 'ti ti-list', })); +