From 2f7cfde73950c81d33a33298ea11f4f72d81270f Mon Sep 17 00:00:00 2001 From: tai-cha Date: Tue, 13 May 2025 10:15:33 +0900 Subject: [PATCH] =?UTF-8?q?=E5=B8=B8=E3=81=AB=E3=82=B5=E3=83=BC=E3=83=90?= =?UTF-8?q?=E3=83=BC=E4=B8=8B=E6=9B=B8=E3=81=8D=E3=81=AB=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E3=81=97=E3=80=81=E4=B8=8A=E9=99=90=E3=82=92=E8=B6=85=E3=81=88?= =?UTF-8?q?=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AE=E3=81=BF=E5=B0=8B=E3=81=AD?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 8 +-- locales/ja-JP.yml | 4 +- .../backend/src/server/api/endpoint-list.ts | 1 + .../api/endpoints/notes/drafts/count.ts | 51 +++++++++++++++++ .../frontend/src/components/MkPostForm.vue | 22 ++++---- packages/misskey-js/etc/misskey-js.api.md | 4 ++ .../misskey-js/src/autogen/apiClientJSDoc.ts | 11 ++++ packages/misskey-js/src/autogen/endpoint.ts | 2 + packages/misskey-js/src/autogen/entities.ts | 1 + packages/misskey-js/src/autogen/types.ts | 55 +++++++++++++++++++ 10 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 packages/backend/src/server/api/endpoints/notes/drafts/count.ts diff --git a/locales/index.d.ts b/locales/index.d.ts index 01a9c4db0a..4070d6e255 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -11916,13 +11916,13 @@ export interface Locale extends ILocale { */ "select": string; /** - * サーバーに下書きを保存しますか? + * 下書きの作成可能数を超えています。 */ - "saveConfirm": string; + "cannotCreateDraftAnymore": string; /** - * ここで「保存しない」を選択しても、下書きは端末内に保存されます。 + * サーバーに下書きを保存するには、下書きを削除する必要があります。ここで「保存しない」を選択しても、下書きは端末内に保存されます。 */ - "saveConfirmDescription": string; + "cannotCreateDraftAnymoreDescription": string; /** * 下書きを削除 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e7fa1ccdb7..e2725ae840 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3187,8 +3187,8 @@ _serverSetupWizard: _drafts: select: "下書きを選択" - saveConfirm: "サーバーに下書きを保存しますか?" - saveConfirmDescription: "ここで「保存しない」を選択しても、下書きは端末内に保存されます。" + cannotCreateDraftAnymore: "下書きの作成可能数を超えています。" + cannotCreateDraftAnymoreDescription: "サーバーに下書きを保存するには、下書きを削除する必要があります。ここで「保存しない」を選択しても、下書きは端末内に保存されます。" delete: "下書きを削除" deleteAreYouSure: "下書きを削除しますか?" noDrafts: "下書きはありません" diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index d17de3f3d9..aba7ec76c1 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -310,6 +310,7 @@ export * as 'notes/drafts' from './endpoints/notes/drafts/list.js'; export * as 'notes/drafts/create' from './endpoints/notes/drafts/create.js'; export * as 'notes/drafts/delete' from './endpoints/notes/drafts/delete.js'; export * as 'notes/drafts/update' from './endpoints/notes/drafts/update.js'; +export * as 'notes/drafts/count' from './endpoints/notes/drafts/count.js'; export * as 'notes/favorites/create' from './endpoints/notes/favorites/create.js'; export * as 'notes/favorites/delete' from './endpoints/notes/favorites/delete.js'; export * as 'notes/featured' from './endpoints/notes/featured.js'; diff --git a/packages/backend/src/server/api/endpoints/notes/drafts/count.ts b/packages/backend/src/server/api/endpoints/notes/drafts/count.ts new file mode 100644 index 0000000000..002a545d32 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/notes/drafts/count.ts @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { NoteDraftsRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['notes', 'drafts'], + + requireCredential: true, + + prohibitMoved: true, + + kind: 'read:account', + + res: { + type: 'number', + optional: false, nullable: false, + description: 'The number of drafts', + }, + + errors: { + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + }, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.noteDraftsRepository) + private noteDraftsRepository: NoteDraftsRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const count = await this.noteDraftsRepository.createQueryBuilder('drafts') + .where('drafts.userId = :meId', { meId: me.id }) + .getCount(); + + return count; + }); + } +} diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index db0cecbd96..53b8580eb3 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -996,19 +996,19 @@ async function post(ev?: MouseEvent) { }); } -async function confirmSavingServerDraft(ev?: Event) { - if (canSaveAsServerDraft.value) { +async function handleSavingServerDraft(ev?: Event) { + const draftCount = await misskeyApi('notes/drafts/count'); + const isOver = draftCount >= $i.policies.noteDraftLimit; + if (canSaveAsServerDraft.value && !isOver) { + return await saveServerDraft(true); + } else if (canSaveAsServerDraft.value) { ev?.stopPropagation(); const { canceled, result } = await os.actions({ type: 'question', - title: i18n.ts._drafts.saveConfirm, - text: i18n.ts._drafts.saveConfirmDescription, + title: i18n.ts._drafts.cannotCreateDraftAnymore, + text: i18n.ts._drafts.cannotCreateDraftAnymoreDescription, actions: [{ - value: 'save' as const, - text: i18n.ts.save, - primary: true, - }, { value: 'discard' as const, text: i18n.ts.dontSave, }, { @@ -1019,8 +1019,6 @@ async function confirmSavingServerDraft(ev?: Event) { if (canceled || result === 'cancel') { return { canClosePostForm: false }; - } else if (result === 'save') { - return await saveServerDraft(true); } else { return { canClosePostForm: true }; } @@ -1030,14 +1028,14 @@ async function confirmSavingServerDraft(ev?: Event) { } async function esc(ev: Event) { - const { canClosePostForm } = await confirmSavingServerDraft(ev); + const { canClosePostForm } = await handleSavingServerDraft(ev); if (canClosePostForm) { emit('esc'); } } async function cancel() { - const { canClosePostForm } = await confirmSavingServerDraft(); + const { canClosePostForm } = await handleSavingServerDraft(); if (canClosePostForm) { emit('cancel'); } diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index cc787d2d23..3f29c1f5e6 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1935,6 +1935,7 @@ declare namespace entities { NotesDeleteRequest, NotesDraftsRequest, NotesDraftsResponse, + NotesDraftsCountResponse, NotesDraftsCreateRequest, NotesDraftsCreateResponse, NotesDraftsDeleteRequest, @@ -2984,6 +2985,9 @@ type NotesCreateResponse = operations['notes___create']['responses']['200']['con // @public (undocumented) type NotesDeleteRequest = operations['notes___delete']['requestBody']['content']['application/json']; +// @public (undocumented) +type NotesDraftsCountResponse = operations['notes___drafts___count']['responses']['200']['content']['application/json']; + // @public (undocumented) type NotesDraftsCreateRequest = operations['notes___drafts___create']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index b7335eb9c2..c2f1c6d877 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -3582,6 +3582,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 2ef18ffbee..c5b285de1f 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -485,6 +485,7 @@ import type { NotesDeleteRequest, NotesDraftsRequest, NotesDraftsResponse, + NotesDraftsCountResponse, NotesDraftsCreateRequest, NotesDraftsCreateResponse, NotesDraftsDeleteRequest, @@ -964,6 +965,7 @@ export type Endpoints = { 'notes/create': { req: NotesCreateRequest; res: NotesCreateResponse }; 'notes/delete': { req: NotesDeleteRequest; res: EmptyResponse }; 'notes/drafts': { req: NotesDraftsRequest; res: NotesDraftsResponse }; + 'notes/drafts/count': { req: EmptyRequest; res: NotesDraftsCountResponse }; 'notes/drafts/create': { req: NotesDraftsCreateRequest; res: NotesDraftsCreateResponse }; 'notes/drafts/delete': { req: NotesDraftsDeleteRequest; res: EmptyResponse }; 'notes/drafts/update': { req: NotesDraftsUpdateRequest; res: NotesDraftsUpdateResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index 587d54ca99..7955cbc048 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -488,6 +488,7 @@ export type NotesCreateResponse = operations['notes___create']['responses']['200 export type NotesDeleteRequest = operations['notes___delete']['requestBody']['content']['application/json']; export type NotesDraftsRequest = operations['notes___drafts']['requestBody']['content']['application/json']; export type NotesDraftsResponse = operations['notes___drafts']['responses']['200']['content']['application/json']; +export type NotesDraftsCountResponse = operations['notes___drafts___count']['responses']['200']['content']['application/json']; export type NotesDraftsCreateRequest = operations['notes___drafts___create']['requestBody']['content']['application/json']; export type NotesDraftsCreateResponse = operations['notes___drafts___create']['responses']['200']['content']['application/json']; export type NotesDraftsDeleteRequest = operations['notes___drafts___delete']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 70b4b98575..e496e52d47 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -3089,6 +3089,15 @@ export type paths = { */ post: operations['notes___drafts']; }; + '/notes/drafts/count': { + /** + * notes/drafts/count + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + post: operations['notes___drafts___count']; + }; '/notes/drafts/create': { /** * notes/drafts/create @@ -24874,6 +24883,52 @@ export type operations = { }; }; }; + /** + * notes/drafts/count + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + notes___drafts___count: { + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': number; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * notes/drafts/create * @description No description provided.