From 8b1f889d1dd30a535d7753d799b4f6ddf98015f5 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Wed, 24 Sep 2025 12:08:03 +0900
Subject: [PATCH] wip
---
locales/index.d.ts | 4 ++++
locales/ja-JP.yml | 1 +
.../core/entities/NoteDraftEntityService.ts | 2 +-
.../src/models/json-schema/note-draft.ts | 5 ++---
.../frontend/src/components/MkPostForm.vue | 21 ++++++++++++++++++-
packages/misskey-js/src/autogen/types.ts | 5 +++--
6 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 5877cc8432..ddbb9e3335 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5553,6 +5553,10 @@ export interface Locale extends ILocale {
* ユーザー指定ノートを作成
*/
"createUserSpecifiedNote": string;
+ /**
+ * 投稿を予約
+ */
+ "schedulePost": string;
"_compression": {
"_quality": {
/**
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1381c1c65b..514181b925 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1383,6 +1383,7 @@ customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カ
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
createUserSpecifiedNote: "ユーザー指定ノートを作成"
+schedulePost: "投稿を予約"
_compression:
_quality:
diff --git a/packages/backend/src/core/entities/NoteDraftEntityService.ts b/packages/backend/src/core/entities/NoteDraftEntityService.ts
index 926c526e87..cdbe2cf643 100644
--- a/packages/backend/src/core/entities/NoteDraftEntityService.ts
+++ b/packages/backend/src/core/entities/NoteDraftEntityService.ts
@@ -105,7 +105,7 @@ export class NoteDraftEntityService implements OnModuleInit {
const packed: Packed<'NoteDraft'> = await awaitAll({
id: noteDraft.id,
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
- scheduledAt: noteDraft.scheduledAt?.toISOString() ?? undefined,
+ scheduledAt: noteDraft.scheduledAt?.getTime() ?? null,
userId: noteDraft.userId,
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
text: text,
diff --git a/packages/backend/src/models/json-schema/note-draft.ts b/packages/backend/src/models/json-schema/note-draft.ts
index 00622fa588..03c32b6548 100644
--- a/packages/backend/src/models/json-schema/note-draft.ts
+++ b/packages/backend/src/models/json-schema/note-draft.ts
@@ -168,9 +168,8 @@ export const packedNoteDraftSchema = {
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
},
scheduledAt: {
- type: 'string',
- optional: true, nullable: true,
- format: 'date-time',
+ type: 'number',
+ optional: false, nullable: true,
},
},
} as const;
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 17f93a4ec8..197530d260 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@@ -199,6 +199,7 @@ if (props.initialVisibleUsers) {
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
}
const reactionAcceptance = ref(store.s.reactionAcceptance);
+const scheduledAt = ref(null);
const draghover = ref(false);
const quoteId = ref(null);
const hasNotSpecifiedMentions = ref(false);
@@ -414,6 +415,7 @@ function watchForDraft() {
watch(localOnly, () => saveDraft());
watch(quoteId, () => saveDraft());
watch(reactionAcceptance, () => saveDraft());
+ watch(scheduledAt, () => saveDraft());
}
function checkMissingMention() {
@@ -605,6 +607,12 @@ function showOtherSettings() {
action: () => {
toggleReactionAcceptance();
},
+ }, {
+ icon: 'ti ti-calendar-time',
+ text: i18n.ts.schedulePost + '...',
+ action: () => {
+ schedule();
+ },
}, { type: 'divider' }, {
type: 'switch',
icon: 'ti ti-eye',
@@ -809,6 +817,7 @@ function saveDraft() {
...( visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
quoteId: quoteId.value,
reactionAcceptance: reactionAcceptance.value,
+ scheduledAt: scheduledAt.value,
},
};
@@ -838,6 +847,7 @@ async function saveServerDraft(clearLocal = false) {
replyId: replyTargetNote.value ? replyTargetNote.value.id : undefined,
channelId: targetChannel.value ? targetChannel.value.id : undefined,
reactionAcceptance: reactionAcceptance.value,
+ scheduledAt: scheduledAt.value,
}).then(() => {
if (clearLocal) {
clear();
@@ -1175,6 +1185,7 @@ function showDraftMenu(ev: MouseEvent) {
renoteTargetNote.value = draft.renote;
replyTargetNote.value = draft.reply;
reactionAcceptance.value = draft.reactionAcceptance;
+ scheduledAt.value = draft.scheduledAt ?? null;
if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
visibleUsers.value = [];
@@ -1220,6 +1231,13 @@ function showDraftMenu(ev: MouseEvent) {
}], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
}
+async function schedule() {
+ const { canceled, result } = await os.inputDate({
+ title: i18n.ts.schedulePost,
+ });
+ if (canceled) return;
+}
+
onMounted(() => {
if (props.autofocus) {
focus();
@@ -1255,6 +1273,7 @@ onMounted(() => {
}
quoteId.value = draft.data.quoteId;
reactionAcceptance.value = draft.data.reactionAcceptance;
+ scheduledAt.value = draft.data.scheduledAt ?? null;
}
}
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index afff4c9301..74ea5fbe5f 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4462,8 +4462,7 @@ export type components = {
localOnly?: boolean;
/** @enum {string|null} */
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
- /** Format: date-time */
- scheduledAt?: string | null;
+ scheduledAt: number | null;
};
NoteReaction: {
/** Format: id */
@@ -29205,6 +29204,7 @@ export interface operations {
expiresAt?: number | null;
expiredAfter?: number | null;
} | null;
+ scheduledAt?: number | null;
};
};
};
@@ -29446,6 +29446,7 @@ export interface operations {
expiresAt?: number | null;
expiredAfter?: number | null;
} | null;
+ scheduledAt?: number | null;
};
};
};