常にサーバー下書きに保存し、上限を超えた場合のみ尋ねるように

This commit is contained in:
tai-cha 2025-05-13 10:15:33 +09:00
parent 6bd0d89ef9
commit 2f7cfde739
No known key found for this signature in database
GPG Key ID: 1D5EE39F870DC283
10 changed files with 141 additions and 18 deletions

8
locales/index.d.ts vendored
View File

@ -11916,13 +11916,13 @@ export interface Locale extends ILocale {
*/
"select": string;
/**
*
*
*/
"saveConfirm": string;
"cannotCreateDraftAnymore": string;
/**
*
*
*/
"saveConfirmDescription": string;
"cannotCreateDraftAnymoreDescription": string;
/**
*
*/

View File

@ -3187,8 +3187,8 @@ _serverSetupWizard:
_drafts:
select: "下書きを選択"
saveConfirm: "サーバーに下書きを保存しますか?"
saveConfirmDescription: "ここで「保存しない」を選択しても、下書きは端末内に保存されます。"
cannotCreateDraftAnymore: "下書きの作成可能数を超えています。"
cannotCreateDraftAnymoreDescription: "サーバーに下書きを保存するには、下書きを削除する必要があります。ここで「保存しない」を選択しても、下書きは端末内に保存されます。"
delete: "下書きを削除"
deleteAreYouSure: "下書きを削除しますか?"
noDrafts: "下書きはありません"

View File

@ -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';

View File

@ -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<typeof meta, typeof paramDef> { // 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;
});
}
}

View File

@ -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');
}

View File

@ -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'];

View File

@ -3582,6 +3582,17 @@ declare module '../api.js' {
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*
* **Credential required**: *Yes* / **Permission**: *read:account*
*/
request<E extends 'notes/drafts/count', P extends Endpoints[E]['req']>(
endpoint: E,
params: P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>>;
/**
* No description provided.
*

View File

@ -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 };

View File

@ -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'];

View File

@ -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.