diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 230249d57..0664ecd11 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,7 +6,7 @@ "features": { "ghcr.io/devcontainers-contrib/features/pnpm:2": {}, "ghcr.io/devcontainers/features/node:1": { - "version": "20.4.0" + "version": "20.3.1" } }, "forwardPorts": [3000], diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 8f8c5a13a..2809cd2ca 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.8' services: app: - build: + build: context: . dockerfile: Dockerfile diff --git a/.editorconfig b/.editorconfig index a6f988f8d..def7baa1a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,6 +6,10 @@ indent_size = 2 charset = utf-8 insert_final_newline = true end_of_line = lf +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false [*.{yml,yaml}] indent_style = space diff --git a/.node-version b/.node-version index bd45cd74a..dd0fe95cc 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20.4.0 +20.3.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index fa129dc27..c118e7e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,24 +14,32 @@ ## 13.x.x (unreleased) -### NOTE -- Node.js 20.4.0以上が必要になりました - ### General - identicon生成を無効にしてパフォーマンスを向上させることができるようになりました - サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました ### Client -- Fix: サーバーメトリクスが90度傾いている -- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正 - deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように - ドライブファイルのメニューで画像をクロップできるように - 画像を動画と同様に簡単に隠せるように - 最初照会したユーザーの最新ノートを受け取るように - オリジナル画像を保持せずにアップロードする場合webpでアップロードされるように(Safari以外) +- 見たことのあるRenoteを省略して表示をオンのときに自分のnoteのrenoteを省略するように +- フォルダーやファイルに対しても開発者モード使用時、IDをコピーできるように +- 引用対象を「もっと見る」で展開した場合、「閉じる」で畳めるように +- Fix: サーバーメトリクスが90度傾いている +- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正 +- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正 +- Fix: ZenUIでポップアップの表示位置がおかしい問題を修正 +- Fix: ページ遷移でスクロール位置が保持されない問題を修正 +- Fix: フォルダーのページネーションが機能しない #11180 +- Fix: 長い文章を投稿する際、プレビューが画面からはみ出る問題を修正 ### Server - JSON.parse の回数を削減することで、ストリーミングのパフォーマンスを向上しました +- nsfwjs のモデルロードを排他することで、重複ロードによってメモリ使用量が増加しないように +- 連合の配送ジョブのパフォーマンスを向上(ロック機構の見直し、Redisキャッシュの活用) +- 全体的なDBクエリのパフォーマンスを向上 ## 13.13.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6b3804f8..896fb6b08 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,7 +106,7 @@ If your language is not listed in Crowdin, please open an issue. ![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg) ## Development -During development, it is useful to use the +During development, it is useful to use the ``` pnpm dev @@ -150,7 +150,7 @@ Prepare DB/Redis for testing. ``` docker compose -f packages/backend/test/docker-compose.yml up ``` -Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`. +Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`. Run all test. ``` diff --git a/Dockerfile b/Dockerfile index c6ddee2ae..5431c28aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax = docker/dockerfile:1.4 -ARG NODE_VERSION=20.4.0-bullseye +ARG NODE_VERSION=20.3.1-bullseye # build assets & compile TypeScript diff --git a/README.md b/README.md index 2aae4bb86..ab4388c2e 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ Misskey logo - + **🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀** - + --- @@ -21,7 +21,7 @@ become a patron - + --- [![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey) diff --git a/assets/title_float.svg b/assets/title_float.svg index 43205ac1c..ed1749e32 100644 --- a/assets/title_float.svg +++ b/assets/title_float.svg @@ -23,13 +23,13 @@ diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue index 3a050889c..c76ce7315 100644 --- a/packages/frontend/src/components/MkSubNoteContent.vue +++ b/packages/frontend/src/components/MkSubNoteContent.vue @@ -15,9 +15,12 @@ {{ i18n.ts.poll }} - + @@ -33,11 +36,13 @@ const props = defineProps<{ note: misskey.entities.Note; }>(); -const collapsed = $ref( +const isLong = props.note.cw == null && props.note.text != null && ( (props.note.text.split('\n').length > 9) || (props.note.text.length > 500) - )); + ); + +const collapsed = $ref(isLong); diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue index 72b70416d..0bc9b0316 100644 --- a/packages/frontend/src/components/MkSuperMenu.vue +++ b/packages/frontend/src/components/MkSuperMenu.vue @@ -46,7 +46,7 @@ defineProps<{ margin: 0 0 8px 0; font-size: 0.9em; } - + > .items { > .item { display: flex; diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index c3b777a12..937e0f079 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -195,7 +195,7 @@ onMounted(() => { .mfm { display: -webkit-box; -webkit-line-clamp: 5; - -webkit-box-orient: vertical; + -webkit-box-orient: vertical; overflow: hidden; } diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts index 7d5a65f41..67243b78f 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts +++ b/packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts @@ -26,7 +26,7 @@ export const Default = { }; }, args: { - + }, parameters: { layout: 'centered', diff --git a/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts index 70817d83c..072628972 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts +++ b/packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts @@ -23,7 +23,7 @@ export const Default = { }; }, args: { - + }, parameters: { layout: 'centered', diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts index f4930aa26..3444605e9 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts @@ -23,7 +23,7 @@ export const Default = { }; }, args: { - + }, parameters: { layout: 'centered', diff --git a/packages/frontend/src/components/MkUserSetupDialog.User.vue b/packages/frontend/src/components/MkUserSetupDialog.User.vue index d66f34f16..b35f27c5b 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.User.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.User.vue @@ -90,7 +90,7 @@ async function follow() { .mfm { display: -webkit-box; -webkit-line-clamp: 5; - -webkit-box-orient: vertical; + -webkit-box-orient: vertical; overflow: hidden; } diff --git a/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts b/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts index 55790602d..f47f4c13d 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts +++ b/packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts @@ -26,7 +26,7 @@ export const Default = { }; }, args: { - + }, parameters: { layout: 'centered', diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts index 2a50a3439..3e756cae9 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts @@ -199,7 +199,7 @@ export default function(props: { } const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5); const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5); - style = `transform: scale(${x}, ${y});`; + style = `transform: scale(${x}, ${y});`; scale = scale * Math.max(x, y); break; } diff --git a/packages/frontend/src/directives/adaptive-bg.ts b/packages/frontend/src/directives/adaptive-bg.ts index 313aad799..83bcd7089 100644 --- a/packages/frontend/src/directives/adaptive-bg.ts +++ b/packages/frontend/src/directives/adaptive-bg.ts @@ -10,7 +10,7 @@ export default { return el.parentElement ? getBgColor(el.parentElement) : 'transparent'; } }; - + const parentBg = getBgColor(src.parentElement); const myBg = window.getComputedStyle(src).backgroundColor; diff --git a/packages/frontend/src/directives/adaptive-border.ts b/packages/frontend/src/directives/adaptive-border.ts index 619c9f0b6..5bd04024b 100644 --- a/packages/frontend/src/directives/adaptive-border.ts +++ b/packages/frontend/src/directives/adaptive-border.ts @@ -10,7 +10,7 @@ export default { return el.parentElement ? getBgColor(el.parentElement) : 'transparent'; } }; - + const parentBg = getBgColor(src.parentElement); const myBg = window.getComputedStyle(src).backgroundColor; diff --git a/packages/frontend/src/directives/panel.ts b/packages/frontend/src/directives/panel.ts index d31dc41ed..8727183d3 100644 --- a/packages/frontend/src/directives/panel.ts +++ b/packages/frontend/src/directives/panel.ts @@ -10,7 +10,7 @@ export default { return el.parentElement ? getBgColor(el.parentElement) : 'transparent'; } }; - + const parentBg = getBgColor(src.parentElement); const myBg = getComputedStyle(document.documentElement).getPropertyValue('--panel'); diff --git a/packages/frontend/src/filters/date.ts b/packages/frontend/src/filters/date.ts index 706b7d60c..9bc9bfe8a 100644 --- a/packages/frontend/src/filters/date.ts +++ b/packages/frontend/src/filters/date.ts @@ -1,4 +1,4 @@ import { dateTimeFormat } from '@/scripts/intl-const'; -export default (d: Date | number | undefined) => dateTimeFormat.format(d); +export default (d: Date | number | undefined) => dateTimeFormat.format(d); export const dateString = (d: string) => dateTimeFormat.format(new Date(d)); diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts index ca4f21f79..f9d04f795 100644 --- a/packages/frontend/src/local-storage.ts +++ b/packages/frontend/src/local-storage.ts @@ -14,7 +14,7 @@ type Keys = 'wallpaper' | 'theme' | 'colorScheme' | - 'useSystemFont' | + 'useSystemFont' | 'fontSize' | 'ui' | 'ui_temp' | diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts index 68977ed79..3a03444de 100644 --- a/packages/frontend/src/nirax.ts +++ b/packages/frontend/src/nirax.ts @@ -1,8 +1,7 @@ // NIRAX --- A lightweight router import { EventEmitter } from 'eventemitter3'; -import { Component, shallowRef, ShallowRef } from 'vue'; -import { pleaseLogin } from '@/scripts/please-login'; +import { Component, onMounted, shallowRef, ShallowRef } from 'vue'; import { safeURIDecode } from '@/scripts/safe-uri-decode'; type RouteDef = { @@ -23,7 +22,7 @@ type ParsedPath = (string | { optional?: boolean; })[]; -export type Resolved = { route: RouteDef; props: Map; child?: Resolved; }; +export type Resolved = { route: RouteDef; props: Map; child?: Resolved; }; function parsePath(path: string): ParsedPath { const res = [] as ParsedPath; @@ -75,15 +74,19 @@ export class Router extends EventEmitter<{ public currentRef: ShallowRef = shallowRef(); public currentRoute: ShallowRef = shallowRef(); private currentPath: string; + private isLoggedIn: boolean; + private notFoundPageComponent: Component; private currentKey = Date.now().toString(); public navHook: ((path: string, flag?: any) => boolean) | null = null; - constructor(routes: Router['routes'], currentPath: Router['currentPath']) { + constructor(routes: Router['routes'], currentPath: Router['currentPath'], isLoggedIn: boolean, notFoundPageComponent: Component) { super(); this.routes = routes; this.currentPath = currentPath; + this.isLoggedIn = isLoggedIn; + this.notFoundPageComponent = notFoundPageComponent; this.navigate(currentPath, null, false); } @@ -159,11 +162,11 @@ export class Router extends EventEmitter<{ if (route.hash != null && hash != null) { props.set(route.hash, safeURIDecode(hash)); } - + if (route.query != null && queryString != null) { const queryObject = [...new URLSearchParams(queryString).entries()] .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {}); - + for (const q in route.query) { const as = route.query[q]; if (queryObject[q]) { @@ -171,7 +174,7 @@ export class Router extends EventEmitter<{ } } } - + return { route, props, @@ -212,8 +215,9 @@ export class Router extends EventEmitter<{ throw new Error('no route found for: ' + path); } - if (res.route.loginRequired) { - pleaseLogin('/'); + if (res.route.loginRequired && !this.isLoggedIn) { + res.route.component = this.notFoundPageComponent; + res.props.set('showLoginPopup', true); } const isSamePath = beforePath === path; @@ -263,13 +267,33 @@ export class Router extends EventEmitter<{ }); } - public replace(path: string, key?: string | null, emitEvent = true) { + public replace(path: string, key?: string | null) { this.navigate(path, key); - if (emitEvent) { - this.emit('replace', { - path, - key: this.currentKey, - }); - } } } + +export function useScrollPositionManager(getScrollContainer: () => HTMLElement, router: Router) { + const scrollPosStore = new Map(); + + onMounted(() => { + const scrollContainer = getScrollContainer(); + + scrollContainer.addEventListener('scroll', () => { + scrollPosStore.set(router.getCurrentKey(), scrollContainer.scrollTop); + }, { passive: true }); + + router.addListener('change', ctx => { + const scrollPos = scrollPosStore.get(ctx.key) ?? 0; + scrollContainer.scroll({ top: scrollPos, behavior: 'instant' }); + if (scrollPos !== 0) { + window.setTimeout(() => { // 遷移直後はタイミングによってはコンポーネントが復元し切ってない可能性も考えられるため少し時間を空けて再度スクロール + scrollContainer.scroll({ top: scrollPos, behavior: 'instant' }); + }, 100); + } + }); + + router.addListener('same', () => { + scrollContainer.scroll({ top: 0, behavior: 'smooth' }); + }); + }); +} diff --git a/packages/frontend/src/pages/about.emojis.vue b/packages/frontend/src/pages/about.emojis.vue index 3744bed10..cc0bf2eed 100644 --- a/packages/frontend/src/pages/about.emojis.vue +++ b/packages/frontend/src/pages/about.emojis.vue @@ -20,7 +20,7 @@ - +
@@ -56,7 +56,7 @@ function search() { const queryarry = q.match(/\:([a-z0-9_]*)\:/g); if (queryarry) { - searchEmojis = customEmojis.value.filter(emoji => + searchEmojis = customEmojis.value.filter(emoji => queryarry.includes(`:${emoji.name}:`), ); } else { diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index 2c9e18b0b..9a5bd88b2 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -36,6 +36,16 @@ + + + + {{ i18n.ts._ad.timezoneinfo }} +
+ + +
+
+
@@ -59,6 +69,7 @@ import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkRadios from '@/components/MkRadios.vue'; +import MkFolder from '@/components/MkFolder.vue'; import FormSplit from '@/components/form/split.vue'; import * as os from '@/os'; import { i18n } from '@/i18n'; @@ -69,6 +80,7 @@ let ads: any[] = $ref([]); // ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化 const localTime = new Date(); const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000; +const daysOfWeek: string[] = [i18n.ts._weekday.sunday, i18n.ts._weekday.monday, i18n.ts._weekday.tuesday, i18n.ts._weekday.wednesday, i18n.ts._weekday.thursday, i18n.ts._weekday.friday, i18n.ts._weekday.saturday]; os.api('admin/ad/list').then(adsResponse => { ads = adsResponse.map(r => { @@ -84,6 +96,11 @@ os.api('admin/ad/list').then(adsResponse => { }); }); +// 選択された曜日(index)のビットフラグを操作する +function toggleDayOfWeek(ad, index) { + ad.dayOfWeek ^= 1 << index; +} + function add() { ads.unshift({ id: null, @@ -95,6 +112,7 @@ function add() { imageUrl: null, expiresAt: null, startsAt: null, + dayOfWeek: 0, }); } @@ -105,6 +123,7 @@ function remove(ad) { }).then(({ canceled }) => { if (canceled) return; ads = ads.filter(x => x !== ad); + if (ad.id == null) return; os.apiWithDialog('admin/ad/delete', { id: ad.id, }); diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 8b083bc89..226eb8d02 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -1,6 +1,6 @@ - +
+ +
diff --git a/packages/frontend/src/ui/minimum.vue b/packages/frontend/src/ui/minimum.vue index e656f00bb..baba9e4da 100644 --- a/packages/frontend/src/ui/minimum.vue +++ b/packages/frontend/src/ui/minimum.vue @@ -1,6 +1,8 @@