From b752dc72e531f6c63f09876a1c68a87a77c03b49 Mon Sep 17 00:00:00 2001 From: taichan <40626578+tai-cha@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:09:23 +0900 Subject: feat: ノートの下書き(draft of note) (#15298) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIp (backend) * Remove unused * 下書きbackend 続き * fix(backedn): visibilityが下書きに反映されない * Update packages/backend/src/postgres.ts Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> * Fix : import order * fix(backend) : createでcwが効かない * FIX FOREGIN KEY * wip: frontend(既存の下書きを挿入) まだ:チャンネル表示、下書きの作成、削除 * WIP: ノート選択ダイアログ 投稿時に下書きを削除 * Promiseに変更 * 連合なし、チャンネルも表示 * Hashtagの値抜け漏れ * hasthagを0文字でも作成可能に * 下書きの保存機構 * chore(misskey-js): build types * localOnly抜け漏れ * チャンネル情報の書き換え * enhance(frontend): ヘッダ部の表示改善 * fix(frontend): ファイル添付できない * fix: no file * fix(frontend): 投票が反映されない * ハッシュタグの展開(コメントアウト外し忘れ) * fix: visibleUserIdsが反映されない * enhance: APIの型を整備 * refactor: 型が整備できたのでasを削除 * Add userhost * fix * enhance: paginationを使う * fix * fix: 自分のアカウントでの投稿でしか下書きを利用できないように 完全に塞ぐことはできないが一応 * :art: * APIのエラーIDを追加 * enhance: スタイル調整 * remove unused code * :art: * fix: ロールポリシーの型 * ロールの編集画面 * ダイアログの挙動改善 * 下書き機能が利用できない場合は表示しないように * refactor * fix: ダブルクリックが効かない問題を修正 * add comments * fix * fix: 保存時のエラーの種別にかかわらずmodalを閉じないように * fix()backend: NoteDraftのreply, renoteの型が間違ってたので修正 (migtrationはあってた) * fix: 投稿フォームを空白にして通常リノートできるやつは下書きとしては弾くように * fix(backend): テキストが0文字でも下書きは保存できるように * Fix(backend): replyIdの型定義がミスっているのを修正 * chore(misskey-js): update types * Add CHANGELOG * lint * 常にサーバー下書きに保存し、上限を超えた場合のみ尋ねるように * NoteDraftServiceにcreate, updateの処理を移譲 * Fix typeerror * remove tooltip * Remove Mkbutton:short and use iconOnly * 不要なコメントの削除 * Remove Short Completely * wip * escキーまわりの挙動を改善 * 下書き選択時に下書き可能数と現在の量が分かるように * cleanUp * wip * wi * wip * Update MkPostForm.vue --------- Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- packages/misskey-js/src/autogen/apiClientJSDoc.ts | 55 +++ packages/misskey-js/src/autogen/endpoint.ts | 13 + packages/misskey-js/src/autogen/entities.ts | 8 + packages/misskey-js/src/autogen/models.ts | 1 + packages/misskey-js/src/autogen/types.ts | 502 ++++++++++++++++++++++ 5 files changed, 579 insertions(+) (limited to 'packages/misskey-js/src') diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 037503cb7a..c638075777 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -3593,6 +3593,61 @@ 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. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + request( + endpoint: E, + params: P, + 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. + * + * **Credential required**: *Yes* / **Permission**: *write: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 45c65ef843..e6c0525f3b 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -488,6 +488,14 @@ import type { NotesCreateRequest, NotesCreateResponse, NotesDeleteRequest, + NotesDraftsCountResponse, + NotesDraftsCreateRequest, + NotesDraftsCreateResponse, + NotesDraftsDeleteRequest, + NotesDraftsListRequest, + NotesDraftsListResponse, + NotesDraftsUpdateRequest, + NotesDraftsUpdateResponse, NotesFavoritesCreateRequest, NotesFavoritesDeleteRequest, NotesFeaturedRequest, @@ -963,6 +971,11 @@ export type Endpoints = { 'notes/conversation': { req: NotesConversationRequest; res: NotesConversationResponse }; 'notes/create': { req: NotesCreateRequest; res: NotesCreateResponse }; 'notes/delete': { req: NotesDeleteRequest; res: EmptyResponse }; + 'notes/drafts/count': { req: EmptyRequest; res: NotesDraftsCountResponse }; + 'notes/drafts/create': { req: NotesDraftsCreateRequest; res: NotesDraftsCreateResponse }; + 'notes/drafts/delete': { req: NotesDraftsDeleteRequest; res: EmptyResponse }; + 'notes/drafts/list': { req: NotesDraftsListRequest; res: NotesDraftsListResponse }; + 'notes/drafts/update': { req: NotesDraftsUpdateRequest; res: NotesDraftsUpdateResponse }; 'notes/favorites/create': { req: NotesFavoritesCreateRequest; res: EmptyResponse }; 'notes/favorites/delete': { req: NotesFavoritesDeleteRequest; res: EmptyResponse }; 'notes/featured': { req: NotesFeaturedRequest; res: NotesFeaturedResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index b7286c1018..1d92094ddf 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -491,6 +491,14 @@ export type NotesConversationResponse = operations['notes___conversation']['resp export type NotesCreateRequest = operations['notes___create']['requestBody']['content']['application/json']; export type NotesCreateResponse = operations['notes___create']['responses']['200']['content']['application/json']; export type NotesDeleteRequest = operations['notes___delete']['requestBody']['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']; +export type NotesDraftsListRequest = operations['notes___drafts___list']['requestBody']['content']['application/json']; +export type NotesDraftsListResponse = operations['notes___drafts___list']['responses']['200']['content']['application/json']; +export type NotesDraftsUpdateRequest = operations['notes___drafts___update']['requestBody']['content']['application/json']; +export type NotesDraftsUpdateResponse = operations['notes___drafts___update']['responses']['200']['content']['application/json']; export type NotesFavoritesCreateRequest = operations['notes___favorites___create']['requestBody']['content']['application/json']; export type NotesFavoritesDeleteRequest = operations['notes___favorites___delete']['requestBody']['content']['application/json']; export type NotesFeaturedRequest = operations['notes___featured']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts index babe2b1859..c3c54b3bbb 100644 --- a/packages/misskey-js/src/autogen/models.ts +++ b/packages/misskey-js/src/autogen/models.ts @@ -14,6 +14,7 @@ export type Ad = components['schemas']['Ad']; export type Announcement = components['schemas']['Announcement']; export type App = components['schemas']['App']; export type Note = components['schemas']['Note']; +export type NoteDraft = components['schemas']['NoteDraft']; export type NoteReaction = components['schemas']['NoteReaction']; export type NoteFavorite = components['schemas']['NoteFavorite']; export type Notification = components['schemas']['Notification']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index a4578bba94..3878a74813 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -2948,6 +2948,51 @@ export type paths = { */ post: operations['notes___delete']; }; + '/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 + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['notes___drafts___create']; + }; + '/notes/drafts/delete': { + /** + * notes/drafts/delete + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['notes___drafts___delete']; + }; + '/notes/drafts/list': { + /** + * notes/drafts/list + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:account* + */ + post: operations['notes___drafts___list']; + }; + '/notes/drafts/update': { + /** + * notes/drafts/update + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:account* + */ + post: operations['notes___drafts___update']; + }; '/notes/favorites/create': { /** * notes/favorites/create @@ -4315,6 +4360,61 @@ export type components = { hasPoll?: boolean; myReaction?: string | null; }; + NoteDraft: { + /** + * Format: id + * @example xxxxxxxxxx + */ + id: string; + /** Format: date-time */ + createdAt: string; + text: string | null; + cw?: string | null; + /** Format: id */ + userId: string; + user: components['schemas']['UserLite']; + /** + * Format: id + * @example xxxxxxxxxx + */ + replyId?: string | null; + /** + * Format: id + * @example xxxxxxxxxx + */ + renoteId?: string | null; + reply?: components['schemas']['Note'] | null; + renote?: components['schemas']['Note'] | null; + /** @enum {string} */ + visibility: 'public' | 'home' | 'followers' | 'specified'; + visibleUserIds?: string[]; + fileIds?: string[]; + files?: components['schemas']['DriveFile'][]; + hashtag?: string; + poll?: { + /** Format: date-time */ + expiresAt?: string | null; + expiredAfter?: number | null; + multiple: boolean; + choices: string[]; + } | null; + /** + * Format: id + * @example xxxxxxxxxx + */ + channelId?: string | null; + channel?: { + id: string; + name: string; + color: string; + isSensitive: boolean; + allowRenoteToExternal: boolean; + userId: string | null; + } | null; + localOnly?: boolean; + /** @enum {string|null} */ + reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null; + }; NoteReaction: { /** * Format: id @@ -5106,6 +5206,7 @@ export type components = { canImportUserLists: boolean; /** @enum {string} */ chatAvailability: 'available' | 'readonly' | 'unavailable'; + noteDraftLimit: number; }; ReversiGameLite: { /** Format: id */ @@ -28586,6 +28687,407 @@ export interface operations { }; }; }; + notes___drafts___count: { + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': number; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + notes___drafts___create: { + requestBody: { + content: { + 'application/json': { + /** + * @default public + * @enum {string} + */ + visibility?: 'public' | 'home' | 'followers' | 'specified'; + visibleUserIds?: string[]; + cw?: string | null; + hashtag?: string | null; + /** @default false */ + localOnly?: boolean; + /** + * @default null + * @enum {string|null} + */ + reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote'; + /** Format: misskey:id */ + replyId?: string | null; + /** Format: misskey:id */ + renoteId?: string | null; + /** Format: misskey:id */ + channelId?: string | null; + text?: string | null; + fileIds?: string[]; + poll?: { + choices: string[]; + multiple?: boolean; + expiresAt?: number | null; + expiredAfter?: number | null; + } | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + createdDraft: components['schemas']['NoteDraft']; + }; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Too many requests */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + notes___drafts___delete: { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + draftId: string; + }; + }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + headers: { + [name: string]: unknown; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + notes___drafts___list: { + requestBody: { + content: { + 'application/json': { + /** @default 30 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['NoteDraft'][]; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + notes___drafts___update: { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + draftId: string; + /** + * @default public + * @enum {string} + */ + visibility?: 'public' | 'home' | 'followers' | 'specified'; + visibleUserIds?: string[]; + cw?: string | null; + hashtag?: string | null; + /** @default false */ + localOnly?: boolean; + /** + * @default null + * @enum {string|null} + */ + reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote'; + /** Format: misskey:id */ + replyId?: string | null; + /** Format: misskey:id */ + renoteId?: string | null; + /** Format: misskey:id */ + channelId?: string | null; + text?: string | null; + fileIds?: string[]; + poll?: { + choices: string[]; + multiple?: boolean; + expiresAt?: number | null; + expiredAfter?: number | null; + } | null; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + updatedDraft: components['schemas']['NoteDraft']; + }; + }; + }; + /** @description Client error */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Too many requests */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; notes___favorites___create: { requestBody: { content: { -- cgit v1.2.3-freya