From 0d24c8843ca725a84cc900411129f98f6c5c2e45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?=
=?UTF-8?q?=E3=81=AB=E3=82=85?=
<17376330+u1-liquid@users.noreply.github.com>
Date: Thu, 9 Jan 2025 10:21:50 +0900
Subject: [PATCH 1/6] =?UTF-8?q?fix(MisskeyIO#866):=20=E3=83=A6=E3=83=BC?=
=?UTF-8?q?=E3=82=B6=E3=83=BC=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=81=8B?=
=?UTF-8?q?=E3=82=89=E3=83=AD=E3=83=BC=E3=83=AB=E3=81=AE=E5=89=B2=E3=82=8A?=
=?UTF-8?q?=E5=BD=93=E3=81=A6=E6=99=82=E3=83=A1=E3=83=A2=E3=82=92=E5=85=A5?=
=?UTF-8?q?=E5=8A=9B=E3=81=97=E3=81=AA=E3=81=84=E3=81=A8=E3=82=AD=E3=83=A3?=
=?UTF-8?q?=E3=83=B3=E3=82=BB=E3=83=AB=E6=89=B1=E3=81=84=E3=81=95=E3=82=8C?=
=?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(Missk?=
=?UTF-8?q?eyIO#877)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/frontend/src/scripts/get-user-menu.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts
index 758a04d373..753a4ee8bb 100644
--- a/packages/frontend/src/scripts/get-user-menu.ts
+++ b/packages/frontend/src/scripts/get-user-menu.ts
@@ -298,7 +298,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
const { canceled: canceled3, result: memo } = await os.inputText({
title: i18n.ts.addMemo,
type: 'textarea',
- placeholder: i18n.ts.memo,
+ default: '',
});
if (canceled3) return;
From 8bd78848736672cb85371f3f4c0290eb9d442fe1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?=
=?UTF-8?q?=E3=81=AB=E3=82=85?=
<17376330+u1-liquid@users.noreply.github.com>
Date: Fri, 10 Jan 2025 14:17:14 +0900
Subject: [PATCH 2/6] =?UTF-8?q?fix(frontend/mobile):=20=E3=83=A2=E3=83=90?=
=?UTF-8?q?=E3=82=A4=E3=83=AB=E3=81=A7kawaii=E3=83=A2=E3=83=BC=E3=83=89?=
=?UTF-8?q?=E3=81=8C=E9=81=A9=E7=94=A8=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84?=
=?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(MisskeyIO#878)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../frontend/src/ui/_common_/navbar-for-mobile.vue | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
index 5d0e065f09..3f4e5bad68 100644
--- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
+++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
@@ -8,7 +8,8 @@ SPDX-License-Identifier: AGPL-3.0-only
@@ -57,7 +58,9 @@ import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
+import { miLocalStorage } from "@/local-storage.js";
+const kawaiiMode = miLocalStorage.getItem('kawaii') === 'true';
const menu = toRef(defaultStore.state, 'menu');
const otherMenuItemIndicated = computed(() => {
for (const def in navbarItemDef) {
@@ -120,6 +123,11 @@ function more() {
aspect-ratio: 1;
}
+.instanceIconAlt {
+ display: inline-block;
+ width: 85%;
+}
+
.bottom {
position: sticky;
bottom: 0;
From 535a6bc756f22ef3118c0077841d94844841c1e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?=
=?UTF-8?q?=E3=81=AB=E3=82=85?=
<17376330+u1-liquid@users.noreply.github.com>
Date: Fri, 10 Jan 2025 14:54:32 +0900
Subject: [PATCH 3/6] =?UTF-8?q?spec(notes/create):=20=E6=8A=95=E7=A8=BF?=
=?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=9Fnote=E3=82=92=E8=BF=94=E3=81=95?=
=?UTF-8?q?=E3=81=AA=E3=81=84=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3?=
=?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=20(MisskeyIO#879)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../backend/src/server/api/endpoints/notes/create.ts | 9 ++++++---
packages/backend/src/server/web/cli.js | 3 ++-
packages/frontend/src/components/MkPostForm.vue | 1 +
packages/frontend/src/pages/reversi/game.vue | 1 +
packages/frontend/src/scripts/get-note-menu.ts | 3 +++
packages/misskey-js/src/autogen/types.ts | 6 ++++++
packages/sw/src/sw.ts | 2 +-
7 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 5bff7f718b..963f3bbfdb 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -40,7 +40,7 @@ export const meta = {
res: {
type: 'object',
- optional: false, nullable: false,
+ optional: true, nullable: false,
properties: {
createdNote: {
type: 'object',
@@ -207,6 +207,7 @@ export const paramDef = {
},
required: ['choices'],
},
+ noCreatedNote: { type: 'boolean', default: false },
},
// (re)note with text, files and poll are optional
if: {
@@ -281,7 +282,8 @@ export default class extends Endpoint
{ // eslint-
const note = await this.notesRepository.findOneBy({ id: idempotent });
if (note) {
logger.info('The request has already been processed.', { noteId: note.id });
- return { createdNote: await this.noteEntityService.pack(note, me) };
+ if (ps.noCreatedNote) return;
+ else return { createdNote: await this.noteEntityService.pack(note, me) };
}
}
@@ -453,7 +455,8 @@ export default class extends Endpoint { // eslint-
await this.redisForTimelines.set(`note:idempotent:${me.id}:${hash}`, note.id, 'EX', 60);
logger.info('Successfully created a note.', { noteId: note.id });
- return {
+ if (ps.noCreatedNote) return;
+ else return {
createdNote: await this.noteEntityService.pack(note, me),
};
} catch (err) {
diff --git a/packages/backend/src/server/web/cli.js b/packages/backend/src/server/web/cli.js
index 30ee77f4d9..2cffd60638 100644
--- a/packages/backend/src/server/web/cli.js
+++ b/packages/backend/src/server/web/cli.js
@@ -41,7 +41,8 @@ window.onload = async () => {
document.getElementById('submit').addEventListener('click', () => {
api('notes/create', {
- text: document.getElementById('text').value
+ text: document.getElementById('text').value,
+ noCreatedNote: true,
}).then(() => {
location.reload();
});
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 00e5f39665..8eacf4f177 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -773,6 +773,7 @@ async function post(ev?: MouseEvent) {
visibility: visibility.value,
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(u => u.id) : undefined,
reactionAcceptance: reactionAcceptance.value,
+ noCreatedNote: true,
};
if (withHashtags.value && hashtags.value && hashtags.value.trim() !== '') {
diff --git a/packages/frontend/src/pages/reversi/game.vue b/packages/frontend/src/pages/reversi/game.vue
index d95dce18a2..865b8425d2 100644
--- a/packages/frontend/src/pages/reversi/game.vue
+++ b/packages/frontend/src/pages/reversi/game.vue
@@ -46,6 +46,7 @@ function start(_game: Misskey.entities.ReversiGameDetailed) {
misskeyApi('notes/create', {
text: i18n.ts._reversi.iStartedAGame + '\n' + location.href,
visibility: 'home',
+ noCreatedNote: true,
});
}
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 92e421cda1..b7d3c1abf4 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -543,6 +543,7 @@ export function getRenoteMenu(props: {
misskeyApi('notes/create', {
renoteId: appearNote.id,
channelId: appearNote.channelId,
+ noCreatedNote: true,
}).then(() => {
os.toast(i18n.ts.renoted);
});
@@ -589,6 +590,7 @@ export function getRenoteMenu(props: {
localOnly,
visibility,
renoteId: appearNote.id,
+ noCreatedNote: true,
}).then(() => {
os.toast(i18n.ts.renoted);
});
@@ -630,6 +632,7 @@ export function getRenoteMenu(props: {
misskeyApi('notes/create', {
renoteId: appearNote.id,
channelId: channel.id,
+ noCreatedNote: true,
}).then(() => {
os.toast(i18n.tsx.renotedToX({ name: channel.name }));
});
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 8a5d1829af..63e97c0f64 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -23333,6 +23333,8 @@ export type operations = {
expiresAt?: number | null;
expiredAfter?: number | null;
}) | null;
+ /** @default false */
+ noCreatedNote?: boolean;
};
};
};
@@ -23345,6 +23347,10 @@ export type operations = {
};
};
};
+ /** @description OK (without any results) */
+ 204: {
+ content: never;
+ };
/** @description Client error */
400: {
content: {
diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts
index cc79d88713..e2f6ab86cd 100644
--- a/packages/sw/src/sw.ts
+++ b/packages/sw/src/sw.ts
@@ -114,7 +114,7 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv
if ('note' in data.body) client = await swos.openPost({ reply: data.body.note }, loginId);
break;
case 'renote':
- if ('note' in data.body) await swos.api('notes/create', loginId, { renoteId: data.body.note.id });
+ if ('note' in data.body) await swos.api('notes/create', loginId, { renoteId: data.body.note.id, noCreatedNote: true });
break;
case 'accept':
switch (data.body.type) {
From 8a0b98aa26801889110feb063076288648ef4dde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?=
=?UTF-8?q?=E3=81=AB=E3=82=85?=
<17376330+u1-liquid@users.noreply.github.com>
Date: Fri, 10 Jan 2025 15:16:28 +0900
Subject: [PATCH 4/6] Sync charts one-at-a-time to reduce database contention
and timeouts (MisskeyIO#880)
(cherry picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/830)
Co-authored-by: Hazelnoot
---
.../src/core/chart/ChartManagementService.ts | 10 +++----
.../processors/CleanChartsProcessorService.ts | 26 +++++++++----------
.../ResyncChartsProcessorService.ts | 8 +++---
.../processors/TickChartsProcessorService.ts | 26 +++++++++----------
4 files changed, 32 insertions(+), 38 deletions(-)
diff --git a/packages/backend/src/core/chart/ChartManagementService.ts b/packages/backend/src/core/chart/ChartManagementService.ts
index 79681370a1..f04c561063 100644
--- a/packages/backend/src/core/chart/ChartManagementService.ts
+++ b/packages/backend/src/core/chart/ChartManagementService.ts
@@ -58,9 +58,9 @@ export class ChartManagementService implements OnApplicationShutdown {
@bindThis
public async start() {
// 20分おきにメモリ情報をDBに書き込み
- this.saveIntervalId = setInterval(() => {
+ this.saveIntervalId = setInterval(async () => {
for (const chart of this.charts) {
- chart.save();
+ await chart.save();
}
}, 1000 * 60 * 20);
}
@@ -69,9 +69,9 @@ export class ChartManagementService implements OnApplicationShutdown {
public async dispose(): Promise {
clearInterval(this.saveIntervalId);
if (process.env.NODE_ENV !== 'test') {
- await Promise.all(
- this.charts.map(chart => chart.save()),
- );
+ for (const chart of this.charts) {
+ await chart.save();
+ }
}
}
diff --git a/packages/backend/src/queue/processors/CleanChartsProcessorService.ts b/packages/backend/src/queue/processors/CleanChartsProcessorService.ts
index 110468801c..19f98c0d51 100644
--- a/packages/backend/src/queue/processors/CleanChartsProcessorService.ts
+++ b/packages/backend/src/queue/processors/CleanChartsProcessorService.ts
@@ -48,20 +48,18 @@ export class CleanChartsProcessorService {
public async process(): Promise {
this.logger.info('Clean charts...');
- await Promise.all([
- this.federationChart.clean(),
- this.notesChart.clean(),
- this.usersChart.clean(),
- this.activeUsersChart.clean(),
- this.instanceChart.clean(),
- this.perUserNotesChart.clean(),
- this.perUserPvChart.clean(),
- this.driveChart.clean(),
- this.perUserReactionsChart.clean(),
- this.perUserFollowingChart.clean(),
- this.perUserDriveChart.clean(),
- this.apRequestChart.clean(),
- ]);
+ await this.federationChart.clean();
+ await this.notesChart.clean();
+ await this.usersChart.clean();
+ await this.activeUsersChart.clean();
+ await this.instanceChart.clean();
+ await this.perUserNotesChart.clean();
+ await this.perUserPvChart.clean();
+ await this.driveChart.clean();
+ await this.perUserReactionsChart.clean();
+ await this.perUserFollowingChart.clean();
+ await this.perUserDriveChart.clean();
+ await this.apRequestChart.clean();
this.logger.succ('All charts successfully cleaned.');
}
diff --git a/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts b/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts
index 570cdf9a75..46e1adf173 100644
--- a/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts
+++ b/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts
@@ -31,11 +31,9 @@ export class ResyncChartsProcessorService {
// TODO: ユーザーごとのチャートも更新する
// TODO: インスタンスごとのチャートも更新する
- await Promise.all([
- this.driveChart.resync(),
- this.notesChart.resync(),
- this.usersChart.resync(),
- ]);
+ await this.driveChart.resync();
+ await this.notesChart.resync();
+ await this.usersChart.resync();
this.logger.succ('All charts successfully resynced.');
}
diff --git a/packages/backend/src/queue/processors/TickChartsProcessorService.ts b/packages/backend/src/queue/processors/TickChartsProcessorService.ts
index 93ec34162d..c09cbccc57 100644
--- a/packages/backend/src/queue/processors/TickChartsProcessorService.ts
+++ b/packages/backend/src/queue/processors/TickChartsProcessorService.ts
@@ -48,20 +48,18 @@ export class TickChartsProcessorService {
public async process(): Promise {
this.logger.info('Tick charts...');
- await Promise.all([
- this.federationChart.tick(false),
- this.notesChart.tick(false),
- this.usersChart.tick(false),
- this.activeUsersChart.tick(false),
- this.instanceChart.tick(false),
- this.perUserNotesChart.tick(false),
- this.perUserPvChart.tick(false),
- this.driveChart.tick(false),
- this.perUserReactionsChart.tick(false),
- this.perUserFollowingChart.tick(false),
- this.perUserDriveChart.tick(false),
- this.apRequestChart.tick(false),
- ]);
+ await this.federationChart.tick(false);
+ await this.notesChart.tick(false);
+ await this.usersChart.tick(false);
+ await this.activeUsersChart.tick(false);
+ await this.instanceChart.tick(false);
+ await this.perUserNotesChart.tick(false);
+ await this.perUserPvChart.tick(false);
+ await this.driveChart.tick(false);
+ await this.perUserReactionsChart.tick(false);
+ await this.perUserFollowingChart.tick(false);
+ await this.perUserDriveChart.tick(false);
+ await this.apRequestChart.tick(false);
this.logger.succ('All charts successfully ticked.');
}
From 31d57f270cc16937cfcd428aa4bcc9342daa399a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?=
=?UTF-8?q?=E3=81=AB=E3=82=85?=
<17376330+u1-liquid@users.noreply.github.com>
Date: Sun, 12 Jan 2025 18:36:16 +0900
Subject: [PATCH 5/6] =?UTF-8?q?feat(frontend/draft):=20=E4=B8=8B=E6=9B=B8?=
=?UTF-8?q?=E3=81=8D=E6=A9=9F=E8=83=BD=E3=81=AE=E6=94=B9=E8=89=AF=E3=83=BB?=
=?UTF-8?q?=E5=BC=B7=E5=8C=96=20(MisskeyIO#881)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
locales/en-US.yml | 2 +
locales/index.d.ts | 8 +
locales/ja-JP.yml | 2 +
locales/ko-KR.yml | 2 +
.../src/components/MkDraftsDialog.vue | 183 +++++++++++++++++
.../frontend/src/components/MkPostForm.vue | 194 ++++++++++++------
.../frontend/src/pages/settings/general.vue | 2 +
.../pages/settings/preferences-backups.vue | 1 +
packages/frontend/src/store.ts | 4 +
.../frontend/src/types/note-draft-item.ts | 38 ++++
10 files changed, 377 insertions(+), 59 deletions(-)
create mode 100644 packages/frontend/src/components/MkDraftsDialog.vue
create mode 100644 packages/frontend/src/types/note-draft-item.ts
diff --git a/locales/en-US.yml b/locales/en-US.yml
index c202d53d18..28652cdbe8 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1317,6 +1317,8 @@ consentAll: "Allow All Items"
consentSelected: "Allow Selected Items"
emailAddressLogin: "Login with email address"
usernameLogin: "Login with username"
+autoloadDrafts: "Automatically load drafts when opening the posting form"
+drafts: "Drafts"
_bubbleGame:
howToPlay: "How to play"
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 045db3c84d..0143fadeed 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5330,6 +5330,14 @@ export interface Locale extends ILocale {
* ユーザー名でログイン
*/
"usernameLogin": string;
+ /**
+ * 投稿フォームを開いたときに下書きを自動で読み込む
+ */
+ "autoloadDrafts": string;
+ /**
+ * 下書き
+ */
+ "drafts": string;
"_bubbleGame": {
/**
* 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 7465bdbb08..df14061cd3 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1326,6 +1326,8 @@ consentAll: "全て許可"
consentSelected: "選択した項目のみ許可"
emailAddressLogin: "メールアドレスでログイン"
usernameLogin: "ユーザー名でログイン"
+autoloadDrafts: "投稿フォームを開いたときに下書きを自動で読み込む"
+drafts: "下書き"
_bubbleGame:
howToPlay: "遊び方"
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index b25f4ec781..929e6ab6ef 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -1314,6 +1314,8 @@ consentAll: "모두 허용"
consentSelected: "선택한 항목만 허용"
emailAddressLogin: "이메일 주소로 로그인"
usernameLogin: "사용자명으로 로그인"
+autoloadDrafts: "글 작성 시 자동으로 임시 저장된 글 불러오기"
+drafts: "임시 저장"
_bubbleGame:
howToPlay: "설명"
diff --git a/packages/frontend/src/components/MkDraftsDialog.vue b/packages/frontend/src/components/MkDraftsDialog.vue
new file mode 100644
index 0000000000..755bb2cf12
--- /dev/null
+++ b/packages/frontend/src/components/MkDraftsDialog.vue
@@ -0,0 +1,183 @@
+
+
+
+ {{ i18n.ts.drafts }}
+
+
+
+
+
+
{{ i18n.ts.nothing }}
+
+
+
+
+
+
+
+ {{ draft.channel.name }}
+
+
+ {{ draft.renote.text }}
+
+
+ {{ draft.reply.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 8eacf4f177..94da01eb77 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -41,6 +41,9 @@ SPDX-License-Identifier: AGPL-3.0-only
+