diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.yml b/.github/ISSUE_TEMPLATE/01_bug-report.yml index f74719989..ac2b39cc1 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.yml +++ b/.github/ISSUE_TEMPLATE/01_bug-report.yml @@ -89,3 +89,9 @@ body: render: markdown validations: required: false + + - type: checkboxes + attributes: + label: Do you want to address this bug yourself? + options: + - label: Yes, I will patch the bug myself and send a pull request diff --git a/.github/ISSUE_TEMPLATE/02_feature-request.yml b/.github/ISSUE_TEMPLATE/02_feature-request.yml index 8420475b3..8d7b0b253 100644 --- a/.github/ISSUE_TEMPLATE/02_feature-request.yml +++ b/.github/ISSUE_TEMPLATE/02_feature-request.yml @@ -14,4 +14,9 @@ body: label: Purpose description: Describe the specific problem or need you think this feature will solve, and who it will help. validations: - required: true \ No newline at end of file + required: true + - type: checkboxes + attributes: + label: Do you want to implement this feature yourself? + options: + - label: Yes, I will implement this by myself and send a pull request diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index d604f9b16..bf92e701b 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -56,7 +56,7 @@ jobs: - name: Upload Artifact uses: actions/upload-artifact@v4 with: - name: api-artifact + name: api-artifact-${{ matrix.api-json-name }} path: ${{ matrix.api-json-name }} save-pr-number: @@ -69,5 +69,5 @@ jobs: echo "$PR_NUMBER" > ./pr_number - uses: actions/upload-artifact@v4 with: - name: api-artifact + name: api-artifact-pr-number path: pr_number diff --git a/.github/workflows/report-api-diff.yml b/.github/workflows/report-api-diff.yml index 309516772..54da8b4a8 100644 --- a/.github/workflows/report-api-diff.yml +++ b/.github/workflows/report-api-diff.yml @@ -19,24 +19,28 @@ jobs: uses: actions/github-script@v7 with: script: | + const fs = require('fs'); let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.payload.workflow_run.id, }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "api-artifact" - })[0]; - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', + let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name.startsWith("api-artifact-") || artifact.name == "api-artifact" }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/api-artifact.zip`, Buffer.from(download.data)); - - name: Extract artifact - run: unzip api-artifact.zip -d artifacts + await Promise.all(matchArtifacts.map(async (artifact) => { + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: artifact.id, + archive_format: 'zip', + }); + await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data)); + })); + - name: Extract all artifacts + run: | + find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d artifacts ';' + ls -la - name: Load PR Number id: load-pr-num run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT" @@ -83,3 +87,11 @@ jobs: pr_number: ${{ steps.load-pr-num.outputs.pr-number }} comment_tag: show_diff filePath: ./output.md + - name: Tell error to PR + uses: thollander/actions-comment-pull-request@v2 + if: failure() && steps.load-pr-num.outputs.pr-number + with: + pr_number: ${{ steps.load-pr-num.outputs.pr-number }} + comment_tag: show_diff_error + message: | + api.jsonの差分作成中にエラーが発生しました。詳細は[Workflowのログ](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})を確認してください。 diff --git a/CHANGELOG.md b/CHANGELOG.md index ac31bc0d2..52f5c07ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,22 @@ --> +## 2023.12.1 + +### General +- Enhance: ローカリゼーションの更新 +- Fix: 自分のdirect noteがuser list timelineに追加されない + +### Client +- Fix: 一部のモデログ(logYellowでの表示対象)について、表示の色が変わらない問題を修正 +- Feat: AiScript専用のMFM構文`$[clickable.ev=EVENTNAME ...]`を追加。`Mk:C:mfm`のオプション`onClickEv`に関数を渡すと、クリック時に`EVENTNAME`を引数にして呼び出す + +### Server +- Enhance: センシティブワードの設定がハッシュタグトレンドにも適用されるようになりました +- Fix: 1702718871541-ffVisibility.jsのdownが壊れている +- Fix:「非センシティブのみ(リモートはいいねのみ)」を設定していても、センシティブに設定されたカスタム絵文字をリアクションできる問題を修正 +- Fix: ロールアサイン時の通知で,ロールアイコンが縮小されずに表示される問題を修正 + ## 2023.12.0 ### Note @@ -99,6 +115,7 @@ - Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように - Enhance: Meilisearchを有効にした検索で、ユーザーのミュートやブロックを考慮するように - Enhance: カスタム絵文字のインポート時の動作を改善 +- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 - Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 - Fix: ロールタイムラインが保存されない問題を修正 - Fix: api.jsonの生成ロジックを改善 #12402 @@ -126,7 +143,6 @@ - Feat: 管理者がコントロールパネルからメールアドレスの照会を行えるようになりました - Enhance: ローカリゼーションの更新 - Enhance: 依存関係の更新 -- Enhance: json-schema(OpenAPIの戻り値として使用されるスキーマ定義)を出来る限り最新化 #12311 ### Client - Enhance: MFMでルビを振れるように diff --git a/SECURITY.md b/SECURITY.md index 2c026a5f3..fc5dec5de 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,7 +1,6 @@ # Reporting Security Issues -If you discover a security issue in Misskey, please report it by sending an -email to [syuilotan@yahoo.co.jp](mailto:syuilotan@yahoo.co.jp). +If you discover a security issue in Misskey, please report it by **[this form](https://github.com/misskey-dev/misskey/security/advisories/new)**. This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository. diff --git a/locales/es-ES.yml b/locales/es-ES.yml index a079cf01f..80cf905f7 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -121,6 +121,12 @@ sensitive: "Marcado como sensible" add: "Agregar" reaction: "Reacción" reactions: "Reacción" +emojiPicker: "Selector de emojis" +pinnedEmojisForReactionSettingDescription: "Puedes seleccionar reacciones para fijarlos en el selector" +pinnedEmojisSettingDescription: "Puedes seleccionar emojis para fijarlos en el selector" +emojiPickerDisplay: "Mostrar el selector de emojis" +overwriteFromPinnedEmojisForReaction: "Sobreescribir las reacciones fijadas" +overwriteFromPinnedEmojis: "Sobreescribir los emojis fijados" reactionSettingDescription2: "Arrastre para reordenar, click para borrar, apriete la tecla + para añadir." rememberNoteVisibility: "Recordar visibilidad" attachCancel: "Quitar adjunto" @@ -260,6 +266,7 @@ removed: "Borrado" removeAreYouSure: "¿Desea borrar \"{x}\"?" deleteAreYouSure: "¿Desea borrar \"{x}\"?" resetAreYouSure: "¿Desea reestablecer?" +areYouSure: "¿Estás conforme?" saved: "Guardado" messaging: "Chat" upload: "Subir" @@ -640,6 +647,7 @@ smtpSecure: "Usar SSL/TLS implícito en la conexión SMTP" smtpSecureInfo: "Apagar cuando se use STARTTLS" testEmail: "Prueba de envío" wordMute: "Silenciar palabras" +hardWordMute: "Filtro de palabra fuerte" regexpError: "Error de la expresión regular" regexpErrorDescription: "Ocurrió un error en la expresión regular en la linea {line} de las palabras muteadas {tab}" instanceMute: "Instancias silenciadas" @@ -873,6 +881,8 @@ makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán pú classic: "Clásico" muteThread: "Silenciar hilo" unmuteThread: "Mostrar hilo" +followingVisibility: "Visibilidad de seguidos" +followersVisibility: "Visibilidad de seguidores" continueThread: "Ver la continuación del hilo" deleteAccountConfirm: "La cuenta será borrada. ¿Está seguro?" incorrectPassword: "La contraseña es incorrecta" @@ -1024,6 +1034,7 @@ sensitiveWords: "Palabras sensibles" sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea" sensitiveWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares." hiddenTags: "Hashtags ocultos" +hiddenTagsDescription: "Selecciona las etiquetas que no se mostrarán en tendencias. Una etiqueta por línea." notesSearchNotAvailable: "No se puede buscar una nota" license: "Licencia" unfavoriteConfirm: "¿Desea quitar de favoritos?" @@ -1152,6 +1163,7 @@ tosAndPrivacyPolicy: "Condiciones de Uso y Política de Privacidad" avatarDecorations: "Decoraciones de avatar" attach: "Acoplar" detach: "Quitar" +detachAll: "Quitar todo" angle: "Ángulo" flip: "Echar de un capirotazo" showAvatarDecorations: "Mostrar decoraciones de avatar" @@ -1165,6 +1177,10 @@ cwNotationRequired: "Si se ha activado \"ocultar contenido\", es necesario propo doReaction: "Añadir reacción" code: "Código" reloadRequiredToApplySettings: "Es necesario recargar para que se aplique la configuración." +remainingN: "Faltan: {n}" +overwriteContentConfirm: "¿Quieres sustituir todo el contenido actual?" +seasonalScreenEffect: "Efectos de pantalla asociados a estaciones" +decorate: "Decorar" _announcement: forExistingUsers: "Solo para usuarios registrados" forExistingUsersDescription: "Este anuncio solo se mostrará a aquellos usuarios registrados en el momento de su publicación. Si se deshabilita esta opción, aquellos usuarios que se registren tras su publicación también lo verán." @@ -1222,6 +1238,45 @@ _initialTutorial: home: "Puedes ver los posts de las cuentas que sigues." local: "Puedes ver los posts de todos los usuarios de este servidor." social: "Se ven los posts de la línea de tiempo de inicio junto con los de la línea de tiempo local." + global: "Puedes ver notas de todos los servidores conectados." + description2: "Puedes cambiar la línea de tiempo en la parte superior de la pantalla cuando quieras." + description3: "Además, hay listas de líneas de tiempo y listas de canales. Para más detalle, por favor visita este enlace: {link}" + _postNote: + title: "Ajustes de publicación de nota" + description1: "Cuando publicas una nota en Misskey, hay varias opciones disponibles. El formulario tiene este aspecto." + _visibility: + description: "Puedes limitar quién puede ver tu nota." + public: "Tu nota será visible para todos los usuarios." + home: "Publicar solo en la línea de tiempo de Inicio. La nota se verá en tu perfil, la verán tus seguidores y también cuando sea renotada." + followers: "Visible solo para seguidores. Sólo tus seguidores podrán ver la nota, y no podrá ser renotada por otras personas." + direct: "Visible sólo para usuarios específicos, y el destinatario será notificado. Puede usarse como alternativa a la mensajería directa." + doNotSendConfidencialOnDirect1: "¡Ten cuidado cuando vayas a enviar información sensible!" + doNotSendConfidencialOnDirect2: "Los administradores del servidor pueden leer lo que escribes. Ten cuidado cuando envíes información sensible en notas directas en servidores no confiables." + localOnly: "Publicando con esta opción seleccionada, la nota no se federará hacia otros servidores. Los usuarios de otros servidores no podrán ver estas notas directamente, sin importar los ajustes seleccionados más arriba." + _cw: + title: "Alerta de contenido (CW)" + description: "En lugar de mostrarse el contenido de la nota, se mostrará lo que escribas en el campo \"comentarios\". Pulsando en \"leer más\" desplegará el contenido de la nota." + _exampleNote: + cw: "¡Esto te hará tener hambre!" + note: "Acabo de comerme un donut de chocolate glaseado 🍩😋" + useCases: "Esto se usa cuando las normas del servidor lo requieren, o para ocultar spoilers o contenido sensible." + _howToMakeAttachmentsSensitive: + title: "¿Cómo puedo marcar adjuntos como contenido sensible?" + description: "Cuando las normas del servidor lo requieran, o el contenido lo requiera, marca la opción de \"contenido sensible\" para el adjunto." + tryThisFile: "¡Prueba a marcar la imagen adjunta como contenido sensible!" + _exampleNote: + note: "Ups, la he liado al abrir la tapa del natto..." + method: "Para marcar un adjunto como sensible, haz clic en la miniatura, abre el menú, y haz clic en \"Marcar como sensible\"." + sensitiveSucceeded: "Cuando adjuntes archivos, por favor, ten en cuenta las normas del servidor para marcarlos como contenido sensible." + doItToContinue: "Marca el archivo adjunto como sensible para continuar." + _done: + title: "¡Has completado el tutorial! 🎉" + description: "Las funciones que mostramos aquí son sólo una pequeña parte. Para más detalles sobre el funcionamiento de Misskey, pulsa en este enlace: {link}" +_timelineDescription: + home: "En la línea de tiempo de Inicio puedes ver las notas de las cuentas a las que sigues." + local: "En la línea de tiempo Local puedes ver las notas de todos los usuarios del servidor." + social: "En la línea de tiempo Social verás las notas de Inicio y Local a la vez." + global: "En la línea de tiempo Global verás las notas de todos los servidores conectados." _serverRules: description: "Un conjunto de reglas que serán mostradas antes del registro. Configurar un sumario de términos de servicio es recomendado." _serverSettings: @@ -1233,6 +1288,7 @@ _serverSettings: manifestJsonOverride: "Sobreescribir manifest.json" shortName: "Nombre corto" shortNameDescription: "Forma corta del nombre de la instancia que puede mostrarse si el nombre completo es demasiado largo." + fanoutTimelineDescription: "Incrementa el rendimiento de forma significativa cuando se obtienen las líneas de tiempo y reduce la carga en la base de datos. A cambio, el uso de la memoria en Redis incrementará. Considera desactivar esta opción en caso de que tu servidor tenga poca memoria o detectes inestabilidad." _accountMigration: moveFrom: "Trasladar de otra cuenta a ésta" moveFromSub: "Crear un alias para otra cuenta." @@ -1490,6 +1546,9 @@ _achievements: _smashTestNotificationButton: title: "Sobrecarga de pruebas" description: "Envía muchas notificaciones de prueba en un corto espacio de tiempo" + _tutorialCompleted: + title: "Diploma del Curso Básico de Misskey" + description: "Tutorial completado" _role: new: "Crear rol" edit: "Editar rol" @@ -1500,7 +1559,9 @@ _role: assignTarget: "Asignar objetivo" descriptionOfAssignTarget: "Manual Para cambiar manualmente lo que se incluye en este rol.\nCondicional configura una condición, y los usuarios que cumplan la condición serán incluídos automáticamente." manual: "manual" + manualRoles: "Roles manuales" conditional: "condicional" + conditionalRoles: "Roles condicionales" condition: "condición" isConditionalRole: "Esto es un rol condicional" isPublic: "Publicar rol" @@ -1549,6 +1610,7 @@ _role: canHideAds: "Puede ocultar anuncios" canSearchNotes: "Uso de la búsqueda de notas" canUseTranslator: "Uso de traductor" + avatarDecorationLimit: "Número máximo de decoraciones de avatar" _condition: isLocal: "Usuario local" isRemote: "Usuario remoto" @@ -1577,6 +1639,7 @@ _emailUnavailable: disposable: "No es un correo reutilizable" mx: "Servidor de correo inválido" smtp: "Servidor de correo no disponible" + banned: "Email no disponible" _ffVisibility: public: "Publicar" followers: "Visible solo para seguidores" @@ -1653,6 +1716,7 @@ _aboutMisskey: donate: "Donar a Misskey" morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰" patrons: "Patrocinadores" + projectMembers: "Miembros del proyecto" _displayOfSensitiveMedia: respect: "Esconder medios marcados como sensibles" ignore: "Mostrar medios marcados como sensibles" @@ -1677,6 +1741,7 @@ _channel: notesCount: "{n} notas" nameAndDescription: "Nombre y descripción" nameOnly: "Sólo nombre" + allowRenoteToExternal: "Permitir renotas y menciones fuera del canal" _menuDisplay: sideFull: "Horizontal" sideIcon: "Horizontal (ícono)" @@ -1780,6 +1845,12 @@ _ago: yearsAgo: "Hace {n} años" invalid: "No hay nada que ver aqui" _timeIn: + seconds: "En {n} segundos" + minutes: "En {n}m" + hours: "En {n}h" + days: "En {n}d" + weeks: "En {n}sem." + months: "En {n}M" years: "En {n} años" _time: second: "Segundos" @@ -1906,6 +1977,7 @@ _widgets: _userList: chooseList: "Seleccione una lista" clicker: "Cliqueador" + birthdayFollowings: "Hoy cumplen años" _cw: hide: "Ocultar" show: "Ver más" @@ -1968,6 +2040,7 @@ _profile: changeAvatar: "Cambiar avatar" changeBanner: "Cambiar banner" verifiedLinkDescription: "Introduciendo una URL que contiene un enlace a tu perfil, se puede mostrar un icono de verificación de propiedad al lado del campo." + avatarDecorationMax: "Puedes añadir un máximo de {max} decoraciones de avatar." _exportOrImport: allNotes: "Todas las notas" favoritedNotes: "Notas favoritas" @@ -2089,6 +2162,7 @@ _notification: pollEnded: "Estan disponibles los resultados de la encuesta" newNote: "Nueva nota" unreadAntennaNote: "Antena {name}" + roleAssigned: "Rol asignado" emptyPushNotificationMessage: "Se han actualizado las notificaciones push" achievementEarned: "Logro desbloqueado" testNotification: "Notificación de prueba" @@ -2110,6 +2184,7 @@ _notification: pollEnded: "La encuesta terminó" receiveFollowRequest: "Recibió una solicitud de seguimiento" followRequestAccepted: "El seguimiento fue aceptado" + roleAssigned: "Rol asignado" achievementEarned: "Logro desbloqueado" app: "Notificaciones desde aplicaciones" _actions: @@ -2255,3 +2330,6 @@ _externalResourceInstaller: _themeInstallFailed: title: "Instalación de tema fallida" description: "Ha ocurrido un problema al instalar el tema. Por favor, inténtalo de nuevo. Se pueden ver más detalles del error en la consola de Javascript." +_dataSaver: + _media: + title: "Cargando Multimedia" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 6cdcc2c24..63d0812e9 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -114,7 +114,7 @@ quote: "인용" inChannelRenote: "채널 내 리노트" inChannelQuote: "채널 내 인용" pinnedNote: "고정된 노트" -pinned: "프로필에 고정" +pinned: "고정하기" you: "나" clickToShow: "클릭하여 보기" sensitive: "열람 주의" @@ -1179,7 +1179,7 @@ code: "문자열" reloadRequiredToApplySettings: "설정을 적용하려면 새로고침을 해야 합니다." remainingN: "나머지: {n}" overwriteContentConfirm: "현재 내용을 덮어쓰기 합니다. 계속 진행하시겠습니까?" -seasonalScreenEffect: "철에 맞는 화면으로 꾸미기" +seasonalScreenEffect: "계절에 따른 효과 보이기" decorate: "장식하기" _announcement: forExistingUsers: "기존 유저에게만 알림" @@ -1641,6 +1641,7 @@ _emailUnavailable: disposable: "임시 이메일 주소는 사용할 수 없습니다" mx: "메일 서버가 올바르지 않습니다" smtp: "메일 서버가 응답하지 않습니다" + banned: "이 메일 주소는 사용할 수 없습니다" _ffVisibility: public: "공개" followers: "팔로워에게만 공개" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 51ba42e66..782f871b1 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -632,11 +632,11 @@ tokenRequested: "允許存取帳戶" pluginTokenRequestedDescription: "此外掛將擁有在此設定的權限。" notificationType: "通知形式" edit: "編輯" -emailServer: "電郵伺服器" -enableEmail: "啟用發送電郵功能" -emailConfigInfo: "用於確認電郵地址及密碼重置" +emailServer: "電子郵件伺服器" +enableEmail: "啟用發送電子郵件功能" +emailConfigInfo: "用於確認電子郵件地址及密碼重置" email: "電子郵件" -emailAddress: "電郵地址" +emailAddress: "電子郵件位址" smtpConfig: "SMTP 伺服器設定" smtpHost: "主機" smtpPort: "埠" @@ -731,7 +731,7 @@ disableShowingAnimatedImages: "不播放動態圖檔" highlightSensitiveMedia: "強調敏感標記" verificationEmailSent: "已發送驗證電子郵件。請點擊進入電子郵件中的鏈接完成驗證。" notSet: "未設定" -emailVerified: "已成功驗證您的電郵" +emailVerified: "已成功驗證您的電子郵件地址" noteFavoritesCount: "我的最愛貼文的數目" pageLikesCount: "頁面被按讚次數" pageLikedCount: "頁面被按讚次數" @@ -783,7 +783,7 @@ capacity: "容量" inUse: "已使用" editCode: "編輯代碼" apply: "套用" -receiveAnnouncementFromInstance: "接收由本實例發出的電郵通知" +receiveAnnouncementFromInstance: "接收來自伺服器的通知" emailNotification: "郵件通知" publish: "發布" inChannelSearch: "頻道内搜尋" @@ -955,7 +955,7 @@ cannotUploadBecauseExceedsFileSizeLimit: "由於超過了檔案大小的限制 beta: "測試版" enableAutoSensitive: "自動 NSFW 判定" enableAutoSensitiveDescription: "如果可用,它將使用機器學習技術判斷檔案是否需要標記為敏感。即使關閉此功能,也可能會依實例規則而自動啟用。" -activeEmailValidationDescription: "積極驗證使用者的電郵地址,以判斷它是否可以通訊。關閉此選項代表只會檢查地址是否符合格式。" +activeEmailValidationDescription: "主動地驗證使用者的電子郵件地址,以確定是否是一次性地址以及是否可以真正與其進行通訊。關閉時,僅檢查格式是否正確。" navbar: "導覽列" shuffle: "隨機" account: "帳戶" @@ -1641,6 +1641,7 @@ _emailUnavailable: disposable: "不是永久可用的地址" mx: "郵件伺服器不正確" smtp: "郵件伺服器沒有應答" + banned: "無法使用此電子郵件地址註冊" _ffVisibility: public: "公開" followers: "只有關注您的使用者能看到" diff --git a/packages/backend/migration/1702718871541-ffVisibility.js b/packages/backend/migration/1702718871541-ffVisibility.js index 24b187313..e9e820c89 100644 --- a/packages/backend/migration/1702718871541-ffVisibility.js +++ b/packages/backend/migration/1702718871541-ffVisibility.js @@ -24,9 +24,11 @@ export class ffVisibility1702718871541 { async down(queryRunner) { await queryRunner.query(`CREATE TYPE "public"."user_profile_ffvisibility_enum" AS ENUM('public', 'followers', 'private')`); await queryRunner.query(`ALTER TABLE "user_profile" ADD "ffVisibility" "public"."user_profile_ffvisibility_enum" NOT NULL DEFAULT 'public'`); + await queryRunner.query(`CREATE CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum") WITH INOUT AS ASSIGNMENT`); - await queryRunner.query(`UPDATE "user_profile" SET ffVisibility = "user_profile"."followingVisibility"`); + await queryRunner.query(`UPDATE "user_profile" SET "ffVisibility" = "followingVisibility"`); await queryRunner.query(`DROP CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum")`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followersVisibility"`); await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followingVisibility"`); await queryRunner.query(`DROP TYPE "public"."user_profile_followersVisibility_enum"`); diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 3a61e353f..7fc780078 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -7,7 +7,6 @@ import { URLSearchParams } from 'node:url'; import * as nodemailer from 'nodemailer'; import { Inject, Injectable } from '@nestjs/common'; import { validate as validateEmail } from 'deep-email-validator'; -import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js'; import { MetaService } from '@/core/MetaService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { DI } from '@/di-symbols.js'; @@ -166,7 +165,10 @@ export class EmailService { email: emailAddress, }); - let validated; + let validated: { + valid: boolean, + reason?: string | null, + }; if (meta.enableActiveEmailValidation) { if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) { diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts index d37899990..5a2417c9c 100644 --- a/packages/backend/src/core/HashtagService.ts +++ b/packages/backend/src/core/HashtagService.ts @@ -15,6 +15,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { FeaturedService } from '@/core/FeaturedService.js'; import { MetaService } from '@/core/MetaService.js'; +import { UtilityService } from '@/core/UtilityService.js'; @Injectable() export class HashtagService { @@ -29,6 +30,7 @@ export class HashtagService { private featuredService: FeaturedService, private idService: IdService, private metaService: MetaService, + private utilityService: UtilityService, ) { } @@ -161,6 +163,7 @@ export class HashtagService { const instance = await this.metaService.fetch(); const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); if (hiddenTags.includes(hashtag)) return; + if (this.utilityService.isSensitiveWordIncluded(hashtag, instance.sensitiveWords)) return; // YYYYMMDDHHmm (10分間隔) const now = new Date(); diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 2bdff872a..ed8d51df1 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -253,7 +253,7 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.visibility === 'public' && data.channel == null) { const sensitiveWords = meta.sensitiveWords; - if (this.isSensitive(data, sensitiveWords)) { + if (this.utilityService.isSensitiveWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) { data.visibility = 'home'; } else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) { data.visibility = 'home'; @@ -704,31 +704,6 @@ export class NoteCreateService implements OnApplicationShutdown { this.index(note); } - @bindThis - private isSensitive(note: Option, sensitiveWord: string[]): boolean { - if (sensitiveWord.length > 0) { - const text = note.cw ?? note.text ?? ''; - if (text === '') return false; - const matched = sensitiveWord.some(filter => { - // represents RegExp - const regexp = filter.match(/^\/(.+)\/(.*)$/); - // This should never happen due to input sanitisation. - if (!regexp) { - const words = filter.split(' '); - return words.every(keyword => text.includes(keyword)); - } - try { - return new RE2(regexp[1], regexp[2]).test(text); - } catch (err) { - // This should never happen due to input sanitisation. - return false; - } - }); - if (matched) return true; - } - return false; - } - @bindThis private isQuote(note: Option): note is Option & { renote: MiNote } { // sync with misc/is-quote.ts @@ -912,6 +887,7 @@ export class NoteCreateService implements OnApplicationShutdown { // ダイレクトのとき、そのリストが対象外のユーザーの場合 if ( note.visibility === 'specified' && + note.userId !== userListMembership.userListUserId && !note.visibleUserIds.some(v => v === userListMembership.userListUserId) ) continue; diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 4233b8d4c..3ca12551b 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -138,7 +138,7 @@ export class ReactionService { reaction = reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; // センシティブ - if ((note.reactionAcceptance === 'nonSensitiveOnly') && emoji.isSensitive) { + if ((note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && emoji.isSensitive) { reaction = FALLBACK; } } else { diff --git a/packages/backend/src/core/UtilityService.ts b/packages/backend/src/core/UtilityService.ts index b95e41167..5dec36c89 100644 --- a/packages/backend/src/core/UtilityService.ts +++ b/packages/backend/src/core/UtilityService.ts @@ -6,6 +6,7 @@ import { URL } from 'node:url'; import { toASCII } from 'punycode'; import { Inject, Injectable } from '@nestjs/common'; +import RE2 from 're2'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { bindThis } from '@/decorators.js'; @@ -41,6 +42,33 @@ export class UtilityService { return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`)); } + @bindThis + public isSensitiveWordIncluded(text: string, sensitiveWords: string[]): boolean { + if (sensitiveWords.length === 0) return false; + if (text === '') return false; + + const regexpregexp = /^\/(.+)\/(.*)$/; + + const matched = sensitiveWords.some(filter => { + // represents RegExp + const regexp = filter.match(regexpregexp); + // This should never happen due to input sanitisation. + if (!regexp) { + const words = filter.split(' '); + return words.every(keyword => text.includes(keyword)); + } + try { + // TODO: RE2インスタンスをキャッシュ + return new RE2(regexp[1], regexp[2]).test(text); + } catch (err) { + // This should never happen due to input sanitisation. + return false; + } + }); + + return matched; + } + @bindThis public extractDbHost(uri: string): string { const url = new URL(uri); diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 6f8494d1d..eef27b972 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -381,6 +381,10 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + shortName: { + type: 'string', + optional: false, nullable: true, + }, objectStorageS3ForcePathStyle: { type: 'boolean', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/federation/stats.ts b/packages/backend/src/server/api/endpoints/federation/stats.ts index 6548142d4..262aa6877 100644 --- a/packages/backend/src/server/api/endpoints/federation/stats.ts +++ b/packages/backend/src/server/api/endpoints/federation/stats.ts @@ -29,37 +29,10 @@ export const meta = { optional: false, nullable: false, items: { - properties: { - id: { type: 'string' }, - firstRetrievedAt: { type: 'string' }, - host: { type: 'string' }, - usersCount: { type: 'number' }, - notesCount: { type: 'number' }, - followingCount: { type: 'number' }, - followersCount: { type: 'number' }, - isNotResponding: { type: 'boolean' }, - isSuspended: { type: 'boolean' }, - isBlocked: { type: 'boolean' }, - softwareName: { type: 'string' }, - softwareVersion: { type: 'string' }, - openRegistrations: { type: 'boolean' }, - name: { type: 'string' }, - description: { type: 'string' }, - maintainerName: { type: 'string' }, - maintainerEmail: { type: 'string' }, - isSilenced: { type: 'boolean' }, - iconUrl: { type: 'string' }, - faviconUrl: { type: 'string' }, - themeColor: { type: 'string' }, - infoUpdatedAt: { - type: 'string', - nullable: true, - }, - latestRequestReceivedAt: { - type: 'string', - nullable: true, - }, - } + type: 'object', + optional: false, + nullable: false, + ref: 'FederationInstance', }, }, otherFollowersCount: { type: 'number' }, @@ -68,42 +41,15 @@ export const meta = { optional: false, nullable: false, items: { - properties: { - id: { type: 'string' }, - firstRetrievedAt: { type: 'string' }, - host: { type: 'string' }, - usersCount: { type: 'number' }, - notesCount: { type: 'number' }, - followingCount: { type: 'number' }, - followersCount: { type: 'number' }, - isNotResponding: { type: 'boolean' }, - isSuspended: { type: 'boolean' }, - isBlocked: { type: 'boolean' }, - softwareName: { type: 'string' }, - softwareVersion: { type: 'string' }, - openRegistrations: { type: 'boolean' }, - name: { type: 'string' }, - description: { type: 'string' }, - maintainerName: { type: 'string' }, - maintainerEmail: { type: 'string' }, - isSilenced: { type: 'boolean' }, - iconUrl: { type: 'string' }, - faviconUrl: { type: 'string' }, - themeColor: { type: 'string' }, - infoUpdatedAt: { - type: 'string', - nullable: true, - }, - latestRequestReceivedAt: { - type: 'string', - nullable: true, - }, - } + type: 'object', + optional: false, + nullable: false, + ref: 'FederationInstance', }, }, otherFollowingCount: { type: 'number' }, }, - } + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 9dd455315..f7c2962bc 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -164,20 +164,34 @@ export const meta = { type: 'object', optional: false, nullable: false, properties: { - place: { + id: { type: 'string', optional: false, nullable: false, + format: 'id', + example: 'xxxxxxxxxx', }, url: { type: 'string', optional: false, nullable: false, format: 'url', }, + place: { + type: 'string', + optional: false, nullable: false, + }, + ratio: { + type: 'number', + optional: false, nullable: false, + }, imageUrl: { type: 'string', optional: false, nullable: false, format: 'url', }, + dayOfWeek: { + type: 'integer', + optional: false, nullable: false, + }, }, }, }, diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index a1561c944..d46bd6979 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -21,6 +21,10 @@ export const meta = { res: { type: 'object', optional: false, nullable: false, + properties: { + sourceLang: { type: 'string' }, + text: { type: 'string' }, + }, }, errors: { diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts index 550e08d7f..535adc9c8 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts @@ -6,7 +6,7 @@ import { parse } from 'acorn'; import { generate } from 'astring'; import { describe, expect, it } from 'vitest'; -import { normalizeClass, unwindCssModuleClassName } from './rollup-plugin-unwind-css-module-class-name'; +import { normalizeClass, unwindCssModuleClassName } from './rollup-plugin-unwind-css-module-class-name.js'; import type * as estree from 'estree'; function parseExpression(code: string): estree.Expression { diff --git a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts b/packages/frontend/src/components/MkAbuseReport.stories.impl.ts index 3b6452962..77e7c84d5 100644 --- a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts +++ b/packages/frontend/src/components/MkAbuseReport.stories.impl.ts @@ -7,8 +7,8 @@ import { action } from '@storybook/addon-actions'; import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { abuseUserReport } from '../../.storybook/fakes'; -import { commonHandlers } from '../../.storybook/mocks'; +import { abuseUserReport } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; import MkAbuseReport from './MkAbuseReport.vue'; export const Default = { render(args) { diff --git a/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts b/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts index b45d54679..dc842b3d1 100644 --- a/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts +++ b/packages/frontend/src/components/MkAbuseReportWindow.stories.impl.ts @@ -7,8 +7,8 @@ import { action } from '@storybook/addon-actions'; import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { userDetailed } from '../../.storybook/fakes'; -import { commonHandlers } from '../../.storybook/mocks'; +import { userDetailed } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; import MkAbuseReportWindow from './MkAbuseReportWindow.vue'; export const Default = { render(args) { diff --git a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts index a6d4d18c1..33c6c2463 100644 --- a/packages/frontend/src/components/MkAccountMoved.stories.impl.ts +++ b/packages/frontend/src/components/MkAccountMoved.stories.impl.ts @@ -5,7 +5,7 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; -import { userDetailed } from '../../.storybook/fakes'; +import { userDetailed } from '../../.storybook/fakes.js'; import MkAccountMoved from './MkAccountMoved.vue'; export const Default = { render(args) { diff --git a/packages/frontend/src/components/MkAchievements.stories.impl.ts b/packages/frontend/src/components/MkAchievements.stories.impl.ts index a67e1def1..6d972467b 100644 --- a/packages/frontend/src/components/MkAchievements.stories.impl.ts +++ b/packages/frontend/src/components/MkAchievements.stories.impl.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { userDetailed } from '../../.storybook/fakes'; -import { commonHandlers } from '../../.storybook/mocks'; +import { userDetailed } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; import MkAchievements from './MkAchievements.vue'; import { ACHIEVEMENT_TYPES } from '@/scripts/achievements.js'; export const Empty = { diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue index b067e94a6..d49eeb032 100644 --- a/packages/frontend/src/components/MkAchievements.vue +++ b/packages/frontend/src/components/MkAchievements.vue @@ -67,7 +67,7 @@ const props = withDefaults(defineProps<{ withDescription: true, }); -const achievements = ref(); +const achievements = ref(null); const lockedAchievements = computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements.value ?? []).some(a => a.name === x))); function fetch() { diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue index 4239cc609..0ff5bd703 100644 --- a/packages/frontend/src/components/MkAsUi.vue +++ b/packages/frontend/src/components/MkAsUi.vue @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ c.text }} - + {{ c.text }}
{{ button.text }} diff --git a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts index 8232759ba..969519386 100644 --- a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts +++ b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts @@ -9,8 +9,8 @@ import { expect } from '@storybook/jest'; import { userEvent, waitFor, within } from '@storybook/testing-library'; import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { userDetailed } from '../../.storybook/fakes'; -import { commonHandlers } from '../../.storybook/mocks'; +import { userDetailed } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; import MkAutocomplete from './MkAutocomplete.vue'; import MkInput from './MkInput.vue'; import { tick } from '@/scripts/test-utils.js'; diff --git a/packages/frontend/src/components/MkAvatars.stories.impl.ts b/packages/frontend/src/components/MkAvatars.stories.impl.ts index 659c0eebd..d41b64695 100644 --- a/packages/frontend/src/components/MkAvatars.stories.impl.ts +++ b/packages/frontend/src/components/MkAvatars.stories.impl.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { userDetailed } from '../../.storybook/fakes'; -import { commonHandlers } from '../../.storybook/mocks'; +import { userDetailed } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; import MkAvatars from './MkAvatars.vue'; export const Default = { render(args) { diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index 14e59acad..40bca11e6 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -26,7 +26,7 @@ export type Captcha = { getResponse(id: string): string; }; -type CaptchaProvider = 'hcaptcha' | 'recaptcha' | 'turnstile'; +export type CaptchaProvider = 'hcaptcha' | 'recaptcha' | 'turnstile'; type CaptchaContainer = { readonly [_ in CaptchaProvider]?: Captcha; diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue index b78252be8..e29cf472f 100644 --- a/packages/frontend/src/components/MkContextMenu.vue +++ b/packages/frontend/src/components/MkContextMenu.vue @@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts index 29e27e137..035b727a3 100644 --- a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts +++ b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts @@ -7,7 +7,7 @@ import { expect } from '@storybook/jest'; import { userEvent, waitFor, within } from '@storybook/testing-library'; import { StoryObj } from '@storybook/vue3'; -import { galleryPost } from '../../.storybook/fakes'; +import { galleryPost } from '../../.storybook/fakes.js'; import MkGalleryPostPreview from './MkGalleryPostPreview.vue'; export const Default = { render(args) { diff --git a/packages/frontend/src/components/MkInviteCode.stories.impl.ts b/packages/frontend/src/components/MkInviteCode.stories.impl.ts index 0127ce061..2ea32dd3b 100644 --- a/packages/frontend/src/components/MkInviteCode.stories.impl.ts +++ b/packages/frontend/src/components/MkInviteCode.stories.impl.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; import { rest } from 'msw'; -import { userDetailed, inviteCode } from '../../.storybook/fakes'; -import { commonHandlers } from '../../.storybook/mocks'; +import { userDetailed, inviteCode } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; import MkInviteCode from './MkInviteCode.vue'; export const Default = { diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue index 8517eff40..1bd0c8e5c 100644 --- a/packages/frontend/src/components/MkLink.vue +++ b/packages/frontend/src/components/MkLink.vue @@ -29,7 +29,7 @@ const self = props.url.startsWith(local); const attr = self ? 'to' : 'href'; const target = self ? null : '_blank'; -const el = ref(); +const el = ref(); useTooltip(el, (showing) => { os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), { diff --git a/packages/frontend/src/components/MkMarquee.vue b/packages/frontend/src/components/MkMarquee.vue index f9d057322..145b60c8e 100644 --- a/packages/frontend/src/components/MkMarquee.vue +++ b/packages/frontend/src/components/MkMarquee.vue @@ -27,7 +27,7 @@ export default { }, }, setup(props) { - const contentEl = ref(); + const contentEl = ref(); function calc() { const eachLength = contentEl.value.offsetWidth / props.repeat; diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index c5be2a2f6..09c5ad922 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -37,7 +37,7 @@ import XBanner from '@/components/MkMediaBanner.vue'; import XImage from '@/components/MkMediaImage.vue'; import XVideo from '@/components/MkMediaVideo.vue'; import * as os from '@/os.js'; -import { FILE_TYPE_BROWSERSAFE } from '@/const'; +import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; import { defaultStore } from '@/store.js'; const props = defineProps<{ diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 0a97cf3db..3026d4f01 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -77,7 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'; import { focusPrev, focusNext } from '@/scripts/focus.js'; import MkSwitchButton from '@/components/MkSwitch.button.vue'; -import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuParent } from '@/types/menu'; +import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuParent } from '@/types/menu.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { isTouchUsing } from '@/scripts/touch.js'; diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 66a5be22c..7d4207f0f 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -250,7 +250,7 @@ const collapsed = ref(appearNote.value.cw == null && isLong); const isDeleted = ref(false); const muted = ref(checkMute(appearNote.value, $i?.mutedWords)); const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords)); -const translation = ref(null); +const translation = ref(null); const translating = ref(false); const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance); const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i.id)); diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index a9fb7fe15..34cf3be89 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -224,7 +224,7 @@ import { claimAchievement } from '@/scripts/achievements.js'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { showMovedDialog } from '@/scripts/show-moved-dialog.js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; -import MkPagination from '@/components/MkPagination.vue'; +import MkPagination, { Paging } from '@/components/MkPagination.vue'; import MkReactionIcon from '@/components/MkReactionIcon.vue'; import MkButton from '@/components/MkButton.vue'; @@ -273,7 +273,7 @@ const isMyRenote = $i && ($i.id === note.value.userId); const showContent = ref(false); const isDeleted = ref(false); const muted = ref($i ? checkWordMute(appearNote.value, $i, $i.mutedWords) : false); -const translation = ref(null); +const translation = ref(null); const translating = ref(false); const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null; const urls = parsed ? extractUrlFromMfm(parsed) : null; @@ -299,7 +299,7 @@ provide('react', (reaction: string) => { }); const tab = ref('replies'); -const reactionTabType = ref(null); +const reactionTabType = ref(null); const renotesPagination = computed(() => ({ endpoint: 'notes/renotes', @@ -307,7 +307,7 @@ const renotesPagination = computed(() => ({ params: { noteId: appearNote.value.id, }, -})); +} satisfies Paging)); const reactionsPagination = computed(() => ({ endpoint: 'notes/reactions', @@ -316,7 +316,7 @@ const reactionsPagination = computed(() => ({ noteId: appearNote.value.id, type: reactionTabType.value, }, -})); +} satisfies Paging)); useNoteCapture({ rootEl: el, diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index 4d422c10a..da7eb36d9 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + >(); const passwordInput = shallowRef>(); const password = ref(''); -const token = ref(null); +const token = ref(null); function onClose() { emit('cancelled'); diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index f800d1652..5e7ca5539 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -185,14 +185,14 @@ watch(showPreview, () => defaultStore.set('showPreview', showPreview.value)); const cw = ref(props.initialCw ?? null); const localOnly = ref(props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly); const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility) as typeof Misskey.noteVisibilities[number]); -const visibleUsers = ref([]); +const visibleUsers = ref([]); if (props.initialVisibleUsers) { props.initialVisibleUsers.forEach(pushVisibleUser); } const reactionAcceptance = ref(defaultStore.state.reactionAcceptance); const autocomplete = ref(null); const draghover = ref(false); -const quoteId = ref(null); +const quoteId = ref(null); const hasNotSpecifiedMentions = ref(false); const recentHashtags = ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]')); const imeText = ref(''); diff --git a/packages/frontend/src/components/MkRolePreview.vue b/packages/frontend/src/components/MkRolePreview.vue index 3e4586cee..4b6b0940b 100644 --- a/packages/frontend/src/components/MkRolePreview.vue +++ b/packages/frontend/src/components/MkRolePreview.vue @@ -28,10 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only