diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.md b/.github/ISSUE_TEMPLATE/01_bug-report.md deleted file mode 100644 index b889d96eb3..0000000000 --- a/.github/ISSUE_TEMPLATE/01_bug-report.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: 🐛 Bug Report -about: Create a report to help us improve -title: '' -labels: ⚠️bug? -assignees: '' - ---- - - - -## 💡 Summary - - - -## 🥰 Expected Behavior - - - -## 🤬 Actual Behavior - - - -## 📝 Steps to Reproduce - -1. -2. -3. - -## 📌 Environment - - - - -### 💻 Frontend -* Model and OS of the device(s): - -* Browser: - -* Server URL: - -* Misskey: - 13.x.x - -### 🛰 Backend (for server admin) - - -* Installation Method or Hosting Service: -* Misskey: 13.x.x -* Node: 20.x.x -* PostgreSQL: 15.x.x -* Redis: 7.x.x -* OS and Architecture: diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.yml b/.github/ISSUE_TEMPLATE/01_bug-report.yml new file mode 100644 index 0000000000..f74719989f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01_bug-report.yml @@ -0,0 +1,91 @@ +name: 🐛 Bug Report +description: Create a report to help us improve +labels: ["⚠️bug?"] + +body: + - type: markdown + attributes: + value: | + Thanks for reporting! + First, in order to avoid duplicate Issues, please search to see if the problem you found has already been reported. + Also, If you are NOT owner/admin of server, PLEASE DONT REPORT SERVER SPECIFIC ISSUES TO HERE! (e.g. feature XXX is not working in misskey.example) Please try with another misskey servers, and if your issue is only reproducible with specific server, contact your server's owner/admin first. + + - type: textarea + attributes: + label: 💡 Summary + description: Tell us what the bug is + validations: + required: true + + - type: textarea + attributes: + label: 🥰 Expected Behavior + description: Tell us what should happen + validations: + required: true + + - type: textarea + attributes: + label: 🤬 Actual Behavior + description: | + Tell us what happens instead of the expected behavior. + Please include errors from the developer console and/or server log files if you have access to them. + validations: + required: true + + - type: textarea + attributes: + label: 📝 Steps to Reproduce + placeholder: | + 1. + 2. + 3. + validations: + required: false + + - type: textarea + attributes: + label: 💻 Frontend Environment + description: | + Tell us where on the platform it happens + DO NOT WRITE "latest". Please provide the specific version. + + Examples: + * Model and OS of the device(s): MacBook Pro (14inch, 2021), macOS Ventura 13.4 + * Browser: Chrome 113.0.5672.126 + * Server URL: misskey.io + * Misskey: 13.x.x + value: | + * Model and OS of the device(s): + * Browser: + * Server URL: + * Misskey: + render: markdown + validations: + required: false + + - type: textarea + attributes: + label: 🛰 Backend Environment (for server admin) + description: | + Tell us where on the platform it happens + DO NOT WRITE "latest". Please provide the specific version. + If you are using a managed service, put that after the version. + + Examples: + * Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment + * Misskey: 13.x.x + * Node: 20.x.x + * PostgreSQL: 15.x.x + * Redis: 7.x.x + * OS and Architecture: Ubuntu 22.04.2 LTS aarch64 + value: | + * Installation Method or Hosting Service: + * Misskey: + * Node: + * PostgreSQL: + * Redis: + * OS and Architecture: + render: markdown + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/02_feature-request.md b/.github/ISSUE_TEMPLATE/02_feature-request.md deleted file mode 100644 index 5045b17712..0000000000 --- a/.github/ISSUE_TEMPLATE/02_feature-request.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: ✨ Feature Request -about: Suggest an idea for this project -title: '' -labels: ✨Feature -assignees: '' - ---- - -## Summary - - diff --git a/.github/ISSUE_TEMPLATE/02_feature-request.yml b/.github/ISSUE_TEMPLATE/02_feature-request.yml new file mode 100644 index 0000000000..17926412ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02_feature-request.yml @@ -0,0 +1,11 @@ +name: ✨ Feature Request +description: Suggest an idea for this project +labels: ["✨Feature"] + +body: + - type: textarea + attributes: + label: Summary + description: Tell us what the suggestion is + validations: + required: true diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c77f8f23..e20c0c6e40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ - Enhance: プラグインを削除した際には、使用されていたアクセストークンも同時に削除されるようになりました - Enhance: プラグインで`Plugin:register_note_view_interruptor`を用いてnoteの代わりにnullを返却することでノートを非表示にできるようになりました - Enhance: AiScript関数`Mk:nyaize()`が追加されました +- Enhance: 情報→ツール はナビゲーションバーにツールとして独立した項目になりました +- Enhance: その他細かなブラッシュアップ - Fix: 投稿フォームでのユーザー変更がプレビューに反映されない問題を修正 - Fix: ユーザーページの ノート > ファイル付き タブにリプライが表示されてしまう - Fix: 「検索」MFMにおいて一部の検索キーワードが正しく認識されない問題を修正 @@ -47,7 +49,7 @@ - Fix: 標準テーマと同じIDを使用してインストールできてしまう問題を修正 ### Server -- Enhance: RedisへのTLのキャッシュをオフにできるように +- Enhance: RedisへのTLのキャッシュ(FTT)をオフにできるように - Enhance: フォローしているチャンネルをフォロー解除した時(またはその逆)、タイムラインに反映される間隔を改善 - Enhance: プロフィールの自己紹介欄のMFMが連合するようになりました - 相手がMisskey v2023.11.0以降である必要があります @@ -59,6 +61,8 @@ - Fix: `hashtags/trend`にてRedisからトレンドの情報が取得できない際にInternal Server Errorになる問題を修正 - Fix: HTLをリロードまたは遡行したとき、フォローしているチャンネルのノートが含まれない問題を修正 #11765 #12181 - Fix: リノートをリノートできるのを修正 +- Fix: アクセストークンを削除すると、通知が取得できなくなる場合がある問題を修正 +- Fix: 自身の宛先なしダイレクト投稿がストリーミングで流れてこない問題を修正 ## 2023.10.2 diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index 3ee7c91f3a..9542815bd7 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; import { In } from 'typeorm'; import { DI } from '@/di-symbols.js'; -import type { AccessTokensRepository, FollowRequestsRepository, NotesRepository, MiUser, UsersRepository } from '@/models/_.js'; +import type { FollowRequestsRepository, NotesRepository, MiUser, UsersRepository } from '@/models/_.js'; import { awaitAll } from '@/misc/prelude/await-all.js'; import type { MiNotification } from '@/models/Notification.js'; import type { MiNote } from '@/models/Note.js'; @@ -40,9 +40,6 @@ export class NotificationEntityService implements OnModuleInit { @Inject(DI.followRequestsRepository) private followRequestsRepository: FollowRequestsRepository, - @Inject(DI.accessTokensRepository) - private accessTokensRepository: AccessTokensRepository, - //private userEntityService: UserEntityService, //private noteEntityService: NoteEntityService, //private customEmojiService: CustomEmojiService, @@ -69,7 +66,6 @@ export class NotificationEntityService implements OnModuleInit { }, ): Promise> { const notification = src; - const token = notification.appAccessTokenId ? await this.accessTokensRepository.findOneByOrFail({ id: notification.appAccessTokenId }) : null; const noteIfNeed = NOTE_REQUIRED_NOTIFICATION_TYPES.has(notification.type) && notification.noteId != null ? ( hint?.packedNotes != null ? hint.packedNotes.get(notification.noteId) @@ -100,8 +96,8 @@ export class NotificationEntityService implements OnModuleInit { } : {}), ...(notification.type === 'app' ? { body: notification.customBody, - header: notification.customHeader ?? token?.name, - icon: notification.customIcon ?? token?.iconUrl, + header: notification.customHeader, + icon: notification.customIcon, } : {}), }); } diff --git a/packages/backend/src/server/api/endpoints/notifications/create.ts b/packages/backend/src/server/api/endpoints/notifications/create.ts index 268628cf76..19bc6fa8d7 100644 --- a/packages/backend/src/server/api/endpoints/notifications/create.ts +++ b/packages/backend/src/server/api/endpoints/notifications/create.ts @@ -42,8 +42,8 @@ export default class extends Endpoint { // eslint- this.notificationService.createNotification(user.id, 'app', { appAccessTokenId: token ? token.id : null, customBody: ps.body, - customHeader: ps.header, - customIcon: ps.icon, + customHeader: ps.header ?? token?.name, + customIcon: ps.icon ?? token?.iconUrl, }); }); } diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 1c882c8d8a..80054d0881 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -56,7 +56,7 @@ class HomeTimelineChannel extends Channel { if (note.visibility === 'followers') { if (!isMe && !Object.hasOwn(this.following, note.userId)) return; } else if (note.visibility === 'specified') { - if (!note.visibleUserIds!.includes(this.user!.id)) return; + if (!isMe && !note.visibleUserIds!.includes(this.user!.id)) return; } if (note.reply) { diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index aa3fc75092..78645982bf 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -67,7 +67,7 @@ class HybridTimelineChannel extends Channel { if (note.visibility === 'followers') { if (!isMe && !Object.hasOwn(this.following, note.userId)) return; } else if (note.visibility === 'specified') { - if (!note.visibleUserIds!.includes(this.user!.id)) return; + if (!isMe && !note.visibleUserIds!.includes(this.user!.id)) return; } // Ignore notes from instances the user has muted diff --git a/packages/frontend/src/components/global/MkFooterSpacer.vue b/packages/frontend/src/components/global/MkFooterSpacer.vue new file mode 100644 index 0000000000..07df76b256 --- /dev/null +++ b/packages/frontend/src/components/global/MkFooterSpacer.vue @@ -0,0 +1,32 @@ + + + + + + + diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 48af4754d7..c740d181f9 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -5,7 +5,7 @@ import { App } from 'vue'; -import Mfm from './global/MkMisskeyFlavoredMarkdown.ts'; +import Mfm from './global/MkMisskeyFlavoredMarkdown.js'; import MkA from './global/MkA.vue'; import MkAcct from './global/MkAcct.vue'; import MkAvatar from './global/MkAvatar.vue'; @@ -16,13 +16,14 @@ import MkUserName from './global/MkUserName.vue'; import MkEllipsis from './global/MkEllipsis.vue'; import MkTime from './global/MkTime.vue'; import MkUrl from './global/MkUrl.vue'; -import I18n from './global/i18n'; +import I18n from './global/i18n.js'; import RouterView from './global/RouterView.vue'; import MkLoading from './global/MkLoading.vue'; import MkError from './global/MkError.vue'; import MkAd from './global/MkAd.vue'; import MkPageHeader from './global/MkPageHeader.vue'; import MkSpacer from './global/MkSpacer.vue'; +import MkFooterSpacer from './global/MkFooterSpacer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue'; export default function(app: App) { @@ -50,6 +51,7 @@ export const components = { MkAd: MkAd, MkPageHeader: MkPageHeader, MkSpacer: MkSpacer, + MkFooterSpacer: MkFooterSpacer, MkStickyContainer: MkStickyContainer, }; @@ -73,6 +75,7 @@ declare module '@vue/runtime-core' { MkAd: typeof MkAd; MkPageHeader: typeof MkPageHeader; MkSpacer: typeof MkSpacer; + MkFooterSpacer: typeof MkFooterSpacer; MkStickyContainer: typeof MkStickyContainer; } } diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index 36d1a3187d..62f578110a 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -6,7 +6,7 @@ import { computed, reactive } from 'vue'; import { $i } from '@/account.js'; import { miLocalStorage } from '@/local-storage.js'; -import { openInstanceMenu } from '@/ui/_common_/common.js'; +import { openInstanceMenu, openToolsMenu } from '@/ui/_common_/common.js'; import { lookup } from '@/scripts/lookup.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; @@ -143,6 +143,13 @@ export const navbarItemDef = reactive({ openInstanceMenu(ev); }, }, + tools: { + title: i18n.ts.tools, + icon: 'ti ti-tool', + action: (ev) => { + openToolsMenu(ev); + }, + }, reload: { title: i18n.ts.reload, icon: 'ti ti-refresh', diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index cfabbbbf65..361a6c8c78 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -23,6 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only + diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 503c39a2ea..062d354dac 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -141,15 +141,9 @@ function focus(): void { tlComponent.focus(); } -const headerActions = $computed(() => [ - ...[deviceKind === 'desktop' ? { - icon: 'ti ti-refresh', - text: i18n.ts.reload, - handler: (ev) => { - console.log('called'); - tlComponent.reloadTimeline(); - }, - } : {}], {icon: 'ti ti-dots', +const headerActions = $computed(() => { + const tmp = [ + {icon: 'ti ti-dots', text: i18n.ts.options, handler: (ev) => { os.popupMenu([{ @@ -168,7 +162,20 @@ const headerActions = $computed(() => [ ref: $$(onlyFiles), }], ev.currentTarget ?? ev.target); }, -}]); +}, + ]; + if (deviceKind === 'desktop') { + tmp.unshift({ + icon: 'ti ti-refresh', + text: i18n.ts.reload, + handler: (ev: Event) => { + console.log('called'); + tlComponent.reloadTimeline(); + }, + }); + } + return tmp; +}); const headerTabs = $computed(() => [...(defaultStore.reactiveState.pinnedUserLists.value.map(l => ({ key: 'list:' + l.id, diff --git a/packages/frontend/src/scripts/worker-multi-dispatch.ts b/packages/frontend/src/scripts/worker-multi-dispatch.ts index 1d184e99a1..7686b687c5 100644 --- a/packages/frontend/src/scripts/worker-multi-dispatch.ts +++ b/packages/frontend/src/scripts/worker-multi-dispatch.ts @@ -71,9 +71,11 @@ export class WorkerMultiDispatch { public isTerminated() { return this.terminated; } + public getWorkers() { return this.workers; } + public getSymbol() { return this.symbol; } diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts index 8de4b42a13..b5298857b2 100644 --- a/packages/frontend/src/ui/_common_/common.ts +++ b/packages/frontend/src/ui/_common_/common.ts @@ -3,12 +3,42 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import type { MenuItem } from '@/types/menu.js'; import * as os from '@/os.js'; import { instance } from '@/instance.js'; import { host } from '@/config.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; +function toolsMenuItems(): MenuItem[] { + return[{ + type: 'link', + to: '/scratchpad', + text: i18n.ts.scratchpad, + icon: 'ti ti-terminal-2', + }, { + type: 'link', + to: '/api-console', + text: 'API Console', + icon: 'ti ti-terminal-2', + }, { + type: 'link', + to: '/clicker', + text: '●👈', + icon: 'ti ti-cookie', + }, ($i && ($i.isAdmin || $i.policies.canManageCustomEmojis)) ? { + type: 'link', + to: '/custom-emojis-manager', + text: i18n.ts.manageCustomEmojis, + icon: 'ti ti-icons', + } : undefined, ($i && ($i.isAdmin || $i.policies.canManageAvatarDecorations)) ? { + type: 'link', + to: '/avatar-decorations', + text: i18n.ts.manageAvatarDecorations, + icon: 'ti ti-sparkles', + } : undefined]; +} + export function openInstanceMenu(ev: MouseEvent) { os.popupMenu([{ text: instance.name ?? host, @@ -47,32 +77,7 @@ export function openInstanceMenu(ev: MouseEvent) { type: 'parent', text: i18n.ts.tools, icon: 'ti ti-tool', - children: [{ - type: 'link', - to: '/scratchpad', - text: i18n.ts.scratchpad, - icon: 'ti ti-terminal-2', - }, { - type: 'link', - to: '/api-console', - text: 'API Console', - icon: 'ti ti-terminal-2', - }, { - type: 'link', - to: '/clicker', - text: '●👈', - icon: 'ti ti-circle', - }, ($i && ($i.isAdmin || $i.policies.canManageCustomEmojis)) ? { - type: 'link', - to: '/custom-emojis-manager', - text: i18n.ts.manageCustomEmojis, - icon: 'ti ti-icons', - } : undefined, ($i && ($i.isAdmin || $i.policies.canManageAvatarDecorations)) ? { - type: 'link', - to: '/avatar-decorations', - text: i18n.ts.manageAvatarDecorations, - icon: 'ti ti-sparkles', - } : undefined], + children: toolsMenuItems(), }, null, (instance.impressumUrl) ? { text: i18n.ts.impressum, icon: 'ti ti-file-invoice', @@ -105,3 +110,9 @@ export function openInstanceMenu(ev: MouseEvent) { align: 'left', }); } + +export function openToolsMenu(ev: MouseEvent) { + os.popupMenu(toolsMenuItems(), ev.currentTarget ?? ev.target, { + align: 'left', + }); +} diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js index 09b4ba726f..b3c7626a39 100644 --- a/packages/shared/.eslintrc.js +++ b/packages/shared/.eslintrc.js @@ -72,13 +72,16 @@ module.exports = { { 'blankLine': 'always', 'prev': 'function', 'next': '*' }, { 'blankLine': 'always', 'prev': '*', 'next': 'function' }, ], - 'lines-between-class-members': ['error', { + "lines-between-class-members": "off", + /* typescript-eslint では enforce に対応してないっぽい + '@typescript-eslint/lines-between-class-members': ['error', { enforce: [{ blankLine: 'always', prev: 'method', next: '*', }] }], + */ '@typescript-eslint/func-call-spacing': ['error', 'never'], '@typescript-eslint/no-explicit-any': ['warn'], '@typescript-eslint/no-unused-vars': ['warn'],