diff --git a/CHANGELOG.md b/CHANGELOG.md index 428f411f8a..c5ff0af61f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,11 +17,16 @@ ### General - Feat: アイコンデコレーション機能 - Enhance: すでにフォローしたすべての人の返信をTLに追加できるように +- Enhance: ローカリゼーションの更新 +- Enhance: 依存関係の更新 ### Client - Feat: プラグイン・テーマを外部サイトから直接インストールできるようになりました - 外部サイトでの実装が必要です。詳細は Misskey Hub をご覧ください https://misskey-hub.net/docs/advanced/publish-on-your-website.html +- Enhance: コードのシンタックスハイライトエンジンをShikiに変更 + - AiScriptのシンタックスハイライトに対応 + - MFMでAiScriptをハイライトする場合、コードブロックの開始部分を ` ```is ` もしくは ` ```aiscript ` としてください - Enhance: データセーバー有効時はアニメーション付きのアバター画像が停止するように - Enhance: プラグインを削除した際には、使用されていたアクセストークンも同時に削除されるようになりました - Enhance: プラグインで`Plugin:register_note_view_interruptor`を用いてnoteの代わりにnullを返却することでノートを非表示にできるようになりました @@ -30,6 +35,7 @@ - Fix: ユーザーページの ノート > ファイル付き タブにリプライが表示されてしまう - Fix: 「検索」MFMにおいて一部の検索キーワードが正しく認識されない問題を修正 - Fix: 一部の言語でMisskey Webがクラッシュする問題を修正 +- Fix: チャンネルの作成・更新時に失敗した場合何も表示されない問題を修正 #11983 ### Server - Enhance: RedisへのTLのキャッシュをオフにできるように @@ -40,6 +46,7 @@ - Fix: RedisへのTLキャッシュが有効の場合にHTL/LTL/STLが空になることがある問題を修正 - Fix: STLでフォローしていないチャンネルが取得される問題を修正 - Fix: `hashtags/trend`にてRedisからトレンドの情報が取得できない際にInternal Server Errorになる問題を修正 +- Fix: HTLをリロードまたは遡行したとき、フォローしているチャンネルのノートが含まれない問題を修正 #11765 ## 2023.10.2 diff --git a/locales/index.d.ts b/locales/index.d.ts index 3c84eb6b02..f20fe9cb97 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1744,6 +1744,7 @@ export interface Locale { "donate": string; "morePatrons": string; "patrons": string; + "projectMembers": string; }; "_displayOfSensitiveMedia": { "respect": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c4f499ce37..496465ddee 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1653,7 +1653,7 @@ _registry: _aboutMisskey: about: "Misskeyはsyuiloによって2014年から開発されている、オープンソースのソフトウェアです。" - contributors: "主なコントリビューター" + contributors: "コントリビューター" allContributors: "全てのコントリビューター" source: "ソースコード" forksource: "当フォークのソースコード" @@ -1661,6 +1661,7 @@ _aboutMisskey: donate: "Misskeyに寄付" morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰" patrons: "支援者" + projectMembers: "プロジェクトメンバー" _displayOfSensitiveMedia: respect: "センシティブ設定されたメディアを隠す" diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 4eeec563d7..19c24a78f4 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -237,7 +237,10 @@ export default class extends Endpoint { // eslint- if (followingChannels.length > 0) { const followingChannelIds = followingChannels.map(x => x.followeeId); - query.andWhere('note.channelId IN (:...followingChannelIds) OR note.channelId IS NULL', { followingChannelIds }); + query.andWhere(new Brackets(qb => { + qb.where('note.channelId IN (:...followingChannelIds)', { followingChannelIds }); + qb.orWhere('note.channelId IS NULL'); + })); } else { query.andWhere('note.channelId IS NULL'); } diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index ac88c1f82b..e048bc4dd2 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -5,7 +5,7 @@ import { Brackets } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; -import type { MiNote, NotesRepository } from '@/models/_.js'; +import type { MiNote, NotesRepository, ChannelFollowingsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueryService } from '@/core/QueryService.js'; import ActiveUsersChart from '@/core/chart/charts/active-users.js'; @@ -58,6 +58,9 @@ export default class extends Endpoint { // eslint- @Inject(DI.notesRepository) private notesRepository: NotesRepository, + @Inject(DI.channelFollowingsRepository) + private channelFollowingsRepository: ChannelFollowingsRepository, + private noteEntityService: NoteEntityService, private activeUsersChart: ActiveUsersChart, private idService: IdService, @@ -160,22 +163,48 @@ export default class extends Endpoint { // eslint- private async getFromDb(ps: { untilId: string | null; sinceId: string | null; limit: number; includeMyRenotes: boolean; includeRenotedMyNotes: boolean; includeLocalRenotes: boolean; withFiles: boolean; withRenotes: boolean; }, me: MiLocalUser) { const followees = await this.userFollowingService.getFollowees(me.id); + const followingChannels = await this.channelFollowingsRepository.find({ + where: { + followerId: me.id, + }, + }); //#region Construct query const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere('note.channelId IS NULL') .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') .leftJoinAndSelect('renote.user', 'renoteUser'); - if (followees.length > 0) { + if (followees.length > 0 && followingChannels.length > 0) { + // ユーザー・チャンネルともにフォローあり const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)]; - - query.andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds }); + const followingChannelIds = followingChannels.map(x => x.followeeId); + query.andWhere(new Brackets(qb => { + qb + .where('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds }) + .orWhere('note.channelId IN (:...followingChannelIds)', { followingChannelIds }); + })); + } else if (followees.length > 0) { + // ユーザーフォローのみ(チャンネルフォローなし) + const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)]; + query + .andWhere('note.channelId IS NULL') + .andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds }); + } else if (followingChannels.length > 0) { + // チャンネルフォローのみ(ユーザーフォローなし) + const followingChannelIds = followingChannels.map(x => x.followeeId); + query.andWhere(new Brackets(qb => { + qb + .where('note.channelId IN (:...followingChannelIds)', { followingChannelIds }) + .orWhere('note.userId = :meId', { meId: me.id }); + })); } else { - query.andWhere('note.userId = :meId', { meId: me.id }); + // フォローなし + query + .andWhere('note.channelId IS NULL') + .andWhere('note.userId = :meId', { meId: me.id }); } query.andWhere(new Brackets(qb => { diff --git a/packages/frontend/package.json b/packages/frontend/package.json index f8492b3e56..fe35519d27 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -29,6 +29,7 @@ "@vue/compiler-sfc": "3.3.7", "astring": "1.8.6", "autosize": "6.0.1", + "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.0.5", "broadcast-channel": "5.5.1", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", "buraha": "0.0.1", @@ -54,11 +55,11 @@ "mfm-js": "0.23.3", "misskey-js": "workspace:*", "photoswipe": "5.4.2", - "prismjs": "1.29.0", "punycode": "2.3.0", "querystring": "0.2.1", "rollup": "4.1.4", "sanitize-html": "2.11.0", + "shiki": "^0.14.5", "sass": "1.69.5", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", @@ -74,7 +75,6 @@ "vanilla-tilt": "1.8.1", "vite": "4.5.0", "vue": "3.3.7", - "vue-prism-editor": "2.0.0-alpha.2", "vuedraggable": "next" }, "devDependencies": { diff --git a/packages/frontend/src/components/MkCode.core.vue b/packages/frontend/src/components/MkCode.core.vue index a1300be1f6..4ec3540419 100644 --- a/packages/frontend/src/components/MkCode.core.vue +++ b/packages/frontend/src/components/MkCode.core.vue @@ -5,21 +5,90 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/components/MkCode.vue b/packages/frontend/src/components/MkCode.vue index 8972b1863b..b39e6ff23c 100644 --- a/packages/frontend/src/components/MkCode.vue +++ b/packages/frontend/src/components/MkCode.vue @@ -4,11 +4,18 @@ SPDX-License-Identifier: AGPL-3.0-only --> + + diff --git a/packages/frontend/src/components/MkCodeEditor.vue b/packages/frontend/src/components/MkCodeEditor.vue new file mode 100644 index 0000000000..2d56a61963 --- /dev/null +++ b/packages/frontend/src/components/MkCodeEditor.vue @@ -0,0 +1,166 @@ + + + + + + + diff --git a/packages/frontend/src/components/MkDateSeparatedList.vue b/packages/frontend/src/components/MkDateSeparatedList.vue index 66d4b542be..e5bdd3781b 100644 --- a/packages/frontend/src/components/MkDateSeparatedList.vue +++ b/packages/frontend/src/components/MkDateSeparatedList.vue @@ -42,6 +42,7 @@ export default defineComponent({ setup(props, { slots, expose }) { const $style = useCssModule(); // カスタムレンダラなので使っても大丈夫 + function getDateText(time: string) { const date = new Date(time).getDate(); const month = new Date(time).getMonth() + 1; @@ -121,6 +122,7 @@ export default defineComponent({ el.style.top = `${el.offsetTop}px`; el.style.left = `${el.offsetLeft}px`; } + function onLeaveCanceled(el: HTMLElement) { el.style.top = ''; el.style.left = ''; diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue index 19c98498f2..b641e188f1 100644 --- a/packages/frontend/src/components/MkDialog.vue +++ b/packages/frontend/src/components/MkDialog.vue @@ -165,6 +165,7 @@ async function ok() { function cancel() { done(true); } + /* function onBgClick() { if (props.cancelableByBgClick) cancel(); diff --git a/packages/frontend/src/components/MkFoldableSection.vue b/packages/frontend/src/components/MkFoldableSection.vue index ed3cb0868b..1ffc95d944 100644 --- a/packages/frontend/src/components/MkFoldableSection.vue +++ b/packages/frontend/src/components/MkFoldableSection.vue @@ -84,6 +84,7 @@ onMounted(() => { return getParentBg(el.parentElement); } } + const rawBg = getParentBg(el.value); const _bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); _bg.setAlpha(0.85); diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index b94f6b395d..7cbe98d830 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -147,11 +147,13 @@ const onGlobalMousedown = (event: MouseEvent) => { }; let childCloseTimer: null | number = null; + function onItemMouseEnter(item) { childCloseTimer = window.setTimeout(() => { closeChild(); }, 300); } + function onItemMouseLeave(item) { if (childCloseTimer) window.clearTimeout(childCloseTimer); } diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index bd79194eeb..3ab6724060 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -526,6 +526,7 @@ function blur() { } const repliesLoaded = ref(false); + function loadReplies() { repliesLoaded.value = true; os.api('notes/children', { @@ -537,6 +538,7 @@ function loadReplies() { } const conversationLoaded = ref(false); + function loadConversation() { conversationLoaded.value = true; os.api('notes/conversation', { diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index 5a87273386..80b469f632 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -87,6 +87,7 @@ function arrayToEntries(entities: MisskeyEntity[]): [string, MisskeyEntity][] { function concatMapWithArray(map: MisskeyEntityMap, entities: MisskeyEntity[]): MisskeyEntityMap { return new Map([...map, ...arrayToEntries(entities)]); } +