Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ec222378c4 | ||
![]() |
ac930a1c6a | ||
![]() |
5ccd5ad56e | ||
![]() |
67da90530b | ||
![]() |
b7f3753615 | ||
![]() |
d21d38509c | ||
![]() |
a59e1c0345 | ||
![]() |
7ab613b394 | ||
![]() |
c00ab0fbe2 | ||
![]() |
87451b1223 | ||
![]() |
d2b61229a3 | ||
![]() |
980584020a | ||
![]() |
a43d0dafa5 | ||
![]() |
d5c1e7e579 | ||
![]() |
55bdf0d618 | ||
![]() |
44f7c13ad4 | ||
![]() |
7bd1a3c8ac | ||
![]() |
4f1981df03 | ||
![]() |
8689a998aa | ||
![]() |
079bb8d722 | ||
![]() |
65c0b6c7da | ||
![]() |
84958af4ce | ||
![]() |
c53b59914b | ||
![]() |
8ffd9ab2d9 | ||
![]() |
0305caf504 | ||
![]() |
3012e4ffe0 | ||
![]() |
585f3c3d3e | ||
![]() |
f1d07dfbed | ||
![]() |
cddfc55110 | ||
![]() |
a2ce072ae7 | ||
![]() |
439563c5d6 | ||
![]() |
962617b4f4 | ||
![]() |
4a202f0f7e | ||
![]() |
6e6b12519a | ||
![]() |
f5f7654f4b | ||
![]() |
5ac4c48ad1 | ||
![]() |
7e18fd18b0 | ||
![]() |
fb30c479ea | ||
![]() |
f40dcbfe13 | ||
![]() |
8755b5f353 | ||
![]() |
691482bb28 | ||
![]() |
4248bb8ce0 | ||
![]() |
a5653e33d3 | ||
![]() |
072dc1c7e6 | ||
![]() |
d76fceae85 | ||
![]() |
86107b2710 | ||
![]() |
a473768bef | ||
![]() |
f7fe13a177 | ||
![]() |
acd29d22eb | ||
![]() |
c228155514 | ||
![]() |
b601b98d5c | ||
![]() |
1cd3419688 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,6 +1,31 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
12.10.0 (2020/02/15)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
* アンテナの受信ソースにグループを指定できるように
|
||||
* 時計ウィジェットを追加
|
||||
* ログアウトせずに新しいアカウントを追加できるように
|
||||
* フォントサイズを設定できるように
|
||||
* APIキー設定を実装
|
||||
|
||||
### 🐛Fixes
|
||||
* v12アップデート後にトップページアクセスでOops!になっちゃうのを修正
|
||||
* drive/files APIのパフォーマンスを改善
|
||||
|
||||
12.9.0 (2020/02/14)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
* カスタム絵文字の管理を強化
|
||||
* 動きのあるMFMを無効にするオプションを追加
|
||||
|
||||
### 🐛Fixes
|
||||
* タイムラインに自分の返信と自分への返信と投稿者自身への返信以外の返信が含まれている問題を修正
|
||||
* グループがない状態でグループチャットを開始しようとするとフリーズする問題を修正
|
||||
* 通知インジケーターがずれる問題を修正
|
||||
* AP: 投稿を削除したときに関係する投稿の削除アクティビティが連合されない問題を修正
|
||||
|
||||
12.8.0 (2020/02/13)
|
||||
--------------------
|
||||
### ✨Improvements
|
||||
|
@@ -1,6 +1,6 @@
|
||||
---
|
||||
_lang_: "English"
|
||||
introMisskey: "Welcome! Misskey is an open source distributed microblogging service.\nCreate \"notes\" to share what's happening or to tell everyone about you📡\nThen send \"reactions\" to respond quickly to everyone's notes👍\nLet's explore a new world🚀"
|
||||
introMisskey: "Welcome! Misskey is an open source and also decentralized microblogging service.\nWrite the \"notes\" to share what is happening now, or send out your own words to everyone 📡\nWith the \"reactions\", you can add your feelings to everyone's notes faster than anyone 👍\nLet's explore the new world 🚀"
|
||||
monthAndDay: "{month}/{day}"
|
||||
search: "Search"
|
||||
notifications: "Notifications"
|
||||
@@ -311,6 +311,7 @@ aboutMisskey: "About Misskey"
|
||||
aboutMisskeyText: "Misskey is an open-source software developed by syuilo since 2014."
|
||||
misskeyMembers: "It is currently developed an maintained by the members listed below:"
|
||||
misskeySource: "Source code is available here:"
|
||||
misskeyTranslation: "Help us with your contribution to translate Misskey:"
|
||||
misskeyDonate: "Help us to keep improving the software by donating here:"
|
||||
morePatrons: "We really appreciate the support of many other helpers not listed here. Thank you! 🥰"
|
||||
patrons: "Backers"
|
||||
@@ -385,6 +386,20 @@ signinWith: "Sign in with {x}"
|
||||
tapSecurityKey: "Tap your security key"
|
||||
or: "Or"
|
||||
uiLanguage: "UI display language"
|
||||
groupInvited: "Invited to group"
|
||||
aboutX: "About {x}"
|
||||
useOsNativeEmojis: "Use the OS native Emojis"
|
||||
noGroups: "No groups"
|
||||
joinOrCreateGroup: "Get invited to join the groups or you can create your own group."
|
||||
noHistory: "No history items"
|
||||
disableAnimatedMfm: "Disable MFM which has animations"
|
||||
doing: "On my way"
|
||||
category: "Category"
|
||||
tags: "Tags"
|
||||
docSource: "Source of this document"
|
||||
createAccount: "Create account"
|
||||
existingAcount: "Existing accounts"
|
||||
regenerate: "Regenerate"
|
||||
_ago:
|
||||
unknown: "Unknown"
|
||||
future: "Future"
|
||||
@@ -468,6 +483,7 @@ _antennaSources:
|
||||
homeTimeline: "Notes from following users"
|
||||
users: "Notes from specific users"
|
||||
userList: "Notes from specific list"
|
||||
userGroup: "Notes from users in the specified group"
|
||||
_weekday:
|
||||
sunday: "Sunday"
|
||||
monday: "Monday"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
---
|
||||
_lang_: "Español"
|
||||
introMisskey: "¡Bienvenido/a! Misskey es un servicio de microblogging descentralizado de código abierto. Escribe \"notas\" para compartir lo que te ocurre ahora o para contar sobre ti a todos. 📡\nCon la función de \"reacciones\", puedes también añadir una reacción rápida a las notas de todos.👍\nExplora un nuevo mundo.🚀"
|
||||
introMisskey: "¡Bienvenido/a! Misskey es un servicio de microblogging descentralizado de código abierto.\nEscribe \"notas\" para compartir lo que te ocurre ahora o para contar sobre ti a todos 📡\nCon la función de \"reacciones\", puedes también añadir una reacción rápida a las notas de todos 👍\nExplora un nuevo mundo 🚀"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "Buscar"
|
||||
notifications: "Notificaciones"
|
||||
@@ -311,6 +311,7 @@ aboutMisskey: "Sobre Misskey"
|
||||
aboutMisskeyText: "Misskey es un software de código abierto, desarrollado por syuilo desde el 2014"
|
||||
misskeyMembers: "Es creado y mantenido por los miembros aquí listados:"
|
||||
misskeySource: "El código fuente está disponible aquí:"
|
||||
misskeyTranslation: "Ayúdanos con tu contribución para traducir Misskey:"
|
||||
misskeyDonate: "Puedes contribuir al desarrollo de Misskey donando aquí:"
|
||||
morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰"
|
||||
patrons: "Patrocinadores"
|
||||
@@ -385,6 +386,20 @@ signinWith: "Inicie sesión con {x}"
|
||||
tapSecurityKey: "Toque la clave de seguridad"
|
||||
or: "O"
|
||||
uiLanguage: "Idioma de visualización de la interfaz"
|
||||
groupInvited: "Invitado al grupo"
|
||||
aboutX: "Acerca de {x}"
|
||||
useOsNativeEmojis: "Usa los emojis nativos de la plataforma"
|
||||
noGroups: "Sin grupos"
|
||||
joinOrCreateGroup: "Obtenga una invitación para unirse al grupos o puede crear su propio grupo."
|
||||
noHistory: "No hay datos en el historial"
|
||||
disableAnimatedMfm: "Deshabilitar MFM que tiene animaciones"
|
||||
doing: "Voy en camino"
|
||||
category: "Categoría"
|
||||
tags: "Etiqueta"
|
||||
docSource: "Fuente de este documento"
|
||||
createAccount: "Crear cuenta"
|
||||
existingAcount: "Cuentas existentes"
|
||||
regenerate: "Regenerar"
|
||||
_ago:
|
||||
unknown: "Desconocido"
|
||||
future: "Futuro"
|
||||
@@ -468,6 +483,7 @@ _antennaSources:
|
||||
homeTimeline: "Notas de los usuarios que sigues"
|
||||
users: "Notas de un usuario o varios"
|
||||
userList: "Notas de los usuarios de una lista"
|
||||
userGroup: "Notas de los usuarios de una grupo"
|
||||
_weekday:
|
||||
sunday: "Domingo"
|
||||
monday: "Lunes"
|
||||
|
@@ -1,5 +1,6 @@
|
||||
---
|
||||
_lang_: "Français"
|
||||
introMisskey: "Bienvenue! Misskey est un service de microblogage décentralisé open source.\nÉcrivez des «notes» pour partager ce qui vous arrive maintenant ou pour parler de vous à tout le monde 📡\nAvec la fonction «réactions», vous pouvez également ajouter une réaction rapide aux notes de chacun 👍\nExplorez un nouveau monde 🚀"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "Rechercher"
|
||||
notifications: "Notifications"
|
||||
@@ -163,6 +164,7 @@ noUsers: "Il n'y a aucun utilisateur·rice"
|
||||
editProfile: "Modifier votre profil"
|
||||
noteDeleteConfirm: "Confirmez-vous la suppression de cette note ?"
|
||||
pinLimitExceeded: "Je ne peux plus épingler"
|
||||
intro: "L'installation de Misskey est terminée! Créons le compte administrateur."
|
||||
done: "Terminé"
|
||||
processing: "Traitement en cours"
|
||||
preview: "Prévisualisation"
|
||||
@@ -264,6 +266,7 @@ registration: "S'inscrire"
|
||||
enableRegistration: "Autoriser n’importe qui à s’enregistrés"
|
||||
invite: "Inviter"
|
||||
proxyRemoteFiles: "Proxy fichiers distants"
|
||||
proxyRemoteFilesDescription: "Si vous activez ce paramètre, les fichiers distants non stockés ou supprimés en raison d'une capacité excédentaire seront affichés via un proxy local et généreront une miniature. Cela n'affectera pas le stockage du serveur."
|
||||
driveCapacityPerLocalAccount: "Volume du Drive par utilisateur local"
|
||||
driveCapacityPerRemoteAccount: "Volume du Drive par utilisateur distant"
|
||||
inMb: "en mégaoctets"
|
||||
@@ -271,6 +274,7 @@ iconUrl: "URL de l'image de l'icône"
|
||||
bannerUrl: "URL de l'image de la bannière"
|
||||
basicInfo: "Informations basiques"
|
||||
pinnedUsers: "Utilisateur·rice épinglé·e"
|
||||
pinnedUsersDescription: "Décrivez les utilisateurs que vous souhaitez définir sur la page \"Découvrir\" séparés par une nouvelle ligne"
|
||||
recaptcha: "reCAPTCHA"
|
||||
enableRecaptcha: "Activation de reCAPTCHA"
|
||||
recaptchaSiteKey: "Clé du site"
|
||||
@@ -304,6 +308,12 @@ popularTags: "Mots-clés populaires"
|
||||
userList: "Listes"
|
||||
about: "Informations"
|
||||
aboutMisskey: "À propos de Misskey"
|
||||
aboutMisskeyText: "Misskey est un logiciel open source, développé par syuilo depuis 2014."
|
||||
misskeyMembers: "Il est développé et maintenu par les membres répertoriés ici:"
|
||||
misskeySource: "Le code source est disponible ici:"
|
||||
misskeyTranslation: "Aidez-nous avec votre contribution à traduire Misskey:"
|
||||
misskeyDonate: "Vous pouvez contribuer au développement de Misskey en faisant un don ici:"
|
||||
morePatrons: "Nous apprécions vraiment le soutien de nombreux autres les soutiens non répertoriés ici. Merci beaucoup à tous! 🥰"
|
||||
patrons: "Supporteurs"
|
||||
administrator: "Administrateur"
|
||||
token: "Jeton"
|
||||
@@ -322,6 +332,7 @@ post: "Notes"
|
||||
posted: "Publié !"
|
||||
autoReloadWhenDisconnected: "Rechargement automatique lorsque le serveur se déconnecte"
|
||||
autoNoteWatch: "Surveiller automatique pour les notes"
|
||||
autoNoteWatchDescription: "Soyez informé des notes auxquelles vous avez réagi ou répondu."
|
||||
reduceUiAnimation: "Réduire l'animation de l'interface"
|
||||
share: "Partager"
|
||||
notFound: "Non trouvé"
|
||||
@@ -375,6 +386,20 @@ signinWith: "Connectez-vous avec {x}"
|
||||
tapSecurityKey: "Touchez la clé de sécurité"
|
||||
or: "OU"
|
||||
uiLanguage: "Langue d'affichage de l'interface"
|
||||
groupInvited: "Invité au groupe"
|
||||
aboutX: "À propos de {x}"
|
||||
useOsNativeEmojis: "Utilisez les emojis natifs de la plateforme"
|
||||
noGroups: "Pas de groupes"
|
||||
joinOrCreateGroup: "Soyez invité à rejoindre les groupes ou vous pouvez créer votre propre groupe."
|
||||
noHistory: "Pas d'historique"
|
||||
disableAnimatedMfm: "Désactiver MFM qui a des animations"
|
||||
doing: "Attends une seconde"
|
||||
category: "Catégories"
|
||||
tags: "Étiquettes"
|
||||
docSource: "Source de ce document"
|
||||
createAccount: "Créer compte"
|
||||
existingAcount: "Comptes existants"
|
||||
regenerate: "Régénérer"
|
||||
_ago:
|
||||
unknown: "Inconnu"
|
||||
future: "Futur"
|
||||
@@ -393,6 +418,7 @@ _time:
|
||||
day: "j"
|
||||
_tutorial:
|
||||
title: "Comment utiliser Misskey"
|
||||
step1_1: "Bienvenue,"
|
||||
_2fa:
|
||||
alreadyRegistered: "Cette étape à déjà été complétée"
|
||||
registerDevice: "S’inscrire l'appareil"
|
||||
@@ -437,6 +463,7 @@ _antennaSources:
|
||||
homeTimeline: "Notes de l'utilisateur auquel je m'abonne"
|
||||
users: "Notes des un ou plusieurs utilisateurs spécifiés"
|
||||
userList: "Notes pour les utilisateurs de la liste spécifiée"
|
||||
userGroup: "Notes pour les utilisateurs de la groupe spécifiée"
|
||||
_weekday:
|
||||
sunday: "Dimanche"
|
||||
monday: "Lundi"
|
||||
@@ -565,6 +592,10 @@ _pages:
|
||||
inspector: "Inspecteur"
|
||||
content: "Bloc de page"
|
||||
variables: "Variables"
|
||||
variables-info: "Vous pouvez créer une page dynamique à l'aide de variables. En tapant le <b>{nom de variable}</b> dans le texte, vous pouvez y incorporer la valeur de la variable. Par exemple, si dans le texte <b>Bonjour {chose} monde!</b> la valeur de la variable (chose) est <b>ai</b>, le texte devient est <b>Bonjour ai monde!</b>."
|
||||
variables-info2: "L'évaluation des variables (le calcul des valeurs) se fait de haut en bas, donc l'variable ne peut pas se référer à une autre qui est en dessous. Par exemple, lorsque les variables <b>A、B、C</b> sont définies, <b>C</b> peut faire référence à <b>A</b> ou <b>B</b>, mais <b>A</b> ne peut pas faire référence à <b>B</b> ou <b>C</b>."
|
||||
variables-info3: "Pour recevoir une entrée utilisateur, ajoutez un bloc \"Entrée\" sur la page et définissez le nom des variables que vous souhaitez stocker dans le champ \"Nom de la variable\" (les variables seront créées automatiquement). Les actions seront exécutées en fonction de l'entrée utilisateur de ces variables."
|
||||
variables-info4: "Les fonctions vous permettent d'organiser le processus de calcul des valeurs sous une forme réutilisable. Pour créer une fonction, créez une variable de type \"fonction\". Une fonction peut avoir un slot (argument) et sa valeur peut être utilisée comme variable dans la fonction. Il existe également une fonction qui prend une fonction comme argument dans la norme AiScript (appelée fonction d'ordre supérieur). En plus des fonctions prédéfinies, elles peuvent être définies instantanément dans ces emplacements de fonction d'ordre supérieur."
|
||||
more-details: "Description"
|
||||
title: "Titre"
|
||||
url: "URL de page"
|
||||
|
@@ -389,6 +389,18 @@ uiLanguage: "UIの表示言語"
|
||||
groupInvited: "グループに招待されました"
|
||||
aboutX: "{x}について"
|
||||
useOsNativeEmojis: "OSネイティブの絵文字を使用"
|
||||
noGroups: "グループがありません"
|
||||
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
|
||||
noHistory: "履歴はありません"
|
||||
disableAnimatedMfm: "動きのあるMFMを無効にする"
|
||||
doing: "やっています"
|
||||
category: "カテゴリ"
|
||||
tags: "タグ"
|
||||
docSource: "このドキュメントのソース"
|
||||
createAccount: "アカウントを作成"
|
||||
existingAcount: "既存のアカウント"
|
||||
regenerate: "再生成"
|
||||
fontSize: "フォントサイズ"
|
||||
|
||||
_ago:
|
||||
unknown: "謎"
|
||||
@@ -479,6 +491,7 @@ _antennaSources:
|
||||
homeTimeline: "フォローしているユーザーのノート"
|
||||
users: "指定した一人または複数のユーザーのノート"
|
||||
userList: "指定したリストのユーザーのノート"
|
||||
userGroup: "指定したグループのユーザーのノート"
|
||||
|
||||
_weekday:
|
||||
sunday: "日曜日"
|
||||
|
@@ -308,9 +308,10 @@ popularTags: "인기 태그"
|
||||
userList: "리스트"
|
||||
about: "정보"
|
||||
aboutMisskey: "Misskey에 대하여"
|
||||
aboutMisskeyText: "Misskey는 syuilo에 의해 2014년부터 개발된 오픈 소스 소프트웨어입니다."
|
||||
misskeyMembers: "현재는 아래 멤버들에 의해 개발 및 유지보수 되고 있습니다."
|
||||
misskeySource: "소스 코드는 여기에서 보실 수 있습니다:"
|
||||
aboutMisskeyText: "Misskey는 syuilo에 의해서 2014년부터 개발되어 온 오픈소스 소프트웨어 입니다."
|
||||
misskeyMembers: "현재는 아래 멤버들에 의해 개발 및 유지보수 되고 있습니다:"
|
||||
misskeySource: "소스코드는 여기에 공개되어 있습니다:"
|
||||
misskeyTranslation: "Misskey의 번역을 함께해 주시길 부탁드립니다:"
|
||||
misskeyDonate: "Misskey에 기부하심으로써 개발에 도움을 주실 수 있습니다:"
|
||||
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
|
||||
patrons: "후원자들"
|
||||
@@ -385,6 +386,20 @@ signinWith: "{x}로 로그인"
|
||||
tapSecurityKey: "보안 키를 터치"
|
||||
or: "혹은"
|
||||
uiLanguage: "UI 표시 언어"
|
||||
groupInvited: "그룹에 초대되었습니다"
|
||||
aboutX: "{x}에 대하여"
|
||||
useOsNativeEmojis: "OS 기본 이모지를 사용"
|
||||
noGroups: "그룹이 없습니다"
|
||||
joinOrCreateGroup: "다른 그룹의 초대를 받거나, 직접 새 그룹을 만들어 보세요."
|
||||
noHistory: "기록이 없습니다"
|
||||
disableAnimatedMfm: "움직임이 있는 MFM을 비활성화"
|
||||
doing: "잠시만요"
|
||||
category: "카테고리"
|
||||
tags: "태그"
|
||||
docSource: "이 문서의 소스"
|
||||
createAccount: "계정 만들기"
|
||||
existingAcount: "기존 계정"
|
||||
regenerate: "다시 생성"
|
||||
_ago:
|
||||
unknown: "알 수 없음"
|
||||
future: "미래"
|
||||
@@ -468,6 +483,7 @@ _antennaSources:
|
||||
homeTimeline: "팔로우중인 유저의 노트"
|
||||
users: "지정한 한 명 혹은 여러 명의 유저의 노트"
|
||||
userList: "지정한 리스트에 속한 유저의 노트"
|
||||
userGroup: "지정한 그룹에 속한 유저의 노트"
|
||||
_weekday:
|
||||
sunday: "일요일"
|
||||
monday: "월요일"
|
||||
|
28
migration/1581695816408-user-group-antenna.ts
Normal file
28
migration/1581695816408-user-group-antenna.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class userGroupAntenna1581695816408 implements MigrationInterface {
|
||||
name = 'userGroupAntenna1581695816408'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD "userGroupJoiningId" character varying(32)`, undefined);
|
||||
await queryRunner.query(`ALTER TYPE "public"."antenna_src_enum" RENAME TO "antenna_src_enum_old"`, undefined);
|
||||
await queryRunner.query(`CREATE TYPE "antenna_src_enum" AS ENUM('home', 'all', 'users', 'list', 'group')`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "src" TYPE "antenna_src_enum" USING "src"::"text"::"antenna_src_enum"`, undefined);
|
||||
await queryRunner.query(`DROP TYPE "antenna_src_enum_old"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "users"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD "users" character varying(1024) array NOT NULL DEFAULT '{}'::varchar[]`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD CONSTRAINT "FK_ccbf5a8c0be4511133dcc50ddeb" FOREIGN KEY ("userGroupJoiningId") REFERENCES "user_group_joining"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP CONSTRAINT "FK_ccbf5a8c0be4511133dcc50ddeb"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "users"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD "users" character varying array NOT NULL DEFAULT '{}'`, undefined);
|
||||
await queryRunner.query(`CREATE TYPE "antenna_src_enum_old" AS ENUM('home', 'all', 'users', 'list')`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "src" TYPE "antenna_src_enum_old" USING "src"::"text"::"antenna_src_enum_old"`, undefined);
|
||||
await queryRunner.query(`DROP TYPE "antenna_src_enum"`, undefined);
|
||||
await queryRunner.query(`ALTER TYPE "antenna_src_enum_old" RENAME TO "antenna_src_enum"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "userGroupJoiningId"`, undefined);
|
||||
}
|
||||
|
||||
}
|
14
migration/1581708415836-drive-user-folder-id-index.ts
Normal file
14
migration/1581708415836-drive-user-folder-id-index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class driveUserFolderIdIndex1581708415836 implements MigrationInterface {
|
||||
name = 'driveUserFolderIdIndex1581708415836'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`CREATE INDEX "IDX_55720b33a61a7c806a8215b825" ON "drive_file" ("userId", "folderId", "id") `, undefined);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`DROP INDEX "IDX_55720b33a61a7c806a8215b825"`, undefined);
|
||||
}
|
||||
|
||||
}
|
54
package.json
54
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.8.0",
|
||||
"version": "12.10.0",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,16 +30,16 @@
|
||||
"lodash": "^4.17.13"
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "7.5.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.26",
|
||||
"@fortawesome/free-brands-svg-icons": "5.12.0",
|
||||
"@fortawesome/free-regular-svg-icons": "5.12.0",
|
||||
"@fortawesome/free-solid-svg-icons": "5.12.0",
|
||||
"@elastic/elasticsearch": "7.6.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.27",
|
||||
"@fortawesome/free-brands-svg-icons": "5.12.1",
|
||||
"@fortawesome/free-regular-svg-icons": "5.12.1",
|
||||
"@fortawesome/free-solid-svg-icons": "5.12.1",
|
||||
"@fortawesome/vue-fontawesome": "0.1.9",
|
||||
"@juggle/resize-observer": "3.0.2",
|
||||
"@koa/cors": "3.0.0",
|
||||
"@koa/multer": "2.0.2",
|
||||
"@koa/router": "8.0.6",
|
||||
"@koa/router": "8.0.8",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.12.0",
|
||||
"@types/cbor": "5.0.0",
|
||||
@@ -54,7 +54,7 @@
|
||||
"@types/js-yaml": "3.12.2",
|
||||
"@types/jsdom": "12.2.4",
|
||||
"@types/katex": "0.11.0",
|
||||
"@types/koa": "2.11.0",
|
||||
"@types/koa": "2.11.1",
|
||||
"@types/koa-bodyparser": "4.3.0",
|
||||
"@types/koa-compress": "2.0.9",
|
||||
"@types/koa-cors": "0.0.0",
|
||||
@@ -69,7 +69,7 @@
|
||||
"@types/lolex": "5.1.0",
|
||||
"@types/markdown-it": "0.0.9",
|
||||
"@types/mocha": "7.0.1",
|
||||
"@types/node": "13.7.0",
|
||||
"@types/node": "13.7.1",
|
||||
"@types/nodemailer": "6.4.0",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/oauth": "0.9.1",
|
||||
@@ -80,7 +80,7 @@
|
||||
"@types/qrcode": "1.3.4",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "2.1.28",
|
||||
"@types/redis": "2.8.14",
|
||||
"@types/redis": "2.8.15",
|
||||
"@types/rename": "1.0.1",
|
||||
"@types/request": "2.48.4",
|
||||
"@types/request-promise-native": "1.0.17",
|
||||
@@ -95,18 +95,18 @@
|
||||
"@types/tmp": "0.1.0",
|
||||
"@types/uuid": "3.4.7",
|
||||
"@types/web-push": "3.3.0",
|
||||
"@types/webpack": "4.41.3",
|
||||
"@types/webpack": "4.41.6",
|
||||
"@types/webpack-stream": "3.2.10",
|
||||
"@types/websocket": "1.0.0",
|
||||
"@types/ws": "7.2.1",
|
||||
"@typescript-eslint/parser": "2.18.0",
|
||||
"@typescript-eslint/parser": "2.19.2",
|
||||
"agentkeepalive": "4.1.0",
|
||||
"animejs": "3.1.0",
|
||||
"apexcharts": "3.15.3",
|
||||
"apexcharts": "3.15.6",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.610.0",
|
||||
"aws-sdk": "2.617.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bull": "3.12.1",
|
||||
"cafy": "15.2.1",
|
||||
@@ -115,7 +115,7 @@
|
||||
"chalk": "3.0.0",
|
||||
"chart.js": "2.9.3",
|
||||
"cli-highlight": "2.1.4",
|
||||
"commander": "4.1.0",
|
||||
"commander": "4.1.1",
|
||||
"content-disposition": "0.5.3",
|
||||
"crc-32": "1.2.0",
|
||||
"css-loader": "3.4.2",
|
||||
@@ -128,7 +128,7 @@
|
||||
"eventemitter3": "4.0.0",
|
||||
"feed": "4.1.0",
|
||||
"fibers": "4.0.2",
|
||||
"file-type": "13.1.2",
|
||||
"file-type": "14.1.2",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"glob": "7.1.6",
|
||||
"gulp": "4.0.2",
|
||||
@@ -144,12 +144,12 @@
|
||||
"hard-source-webpack-plugin": "0.13.1",
|
||||
"html-minifier": "4.0.0",
|
||||
"http-signature": "1.3.1",
|
||||
"https-proxy-agent": "4.0.0",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"is-root": "2.1.0",
|
||||
"is-svg": "4.2.1",
|
||||
"js-yaml": "3.13.1",
|
||||
"jsdom": "16.0.1",
|
||||
"jsdom": "16.1.0",
|
||||
"json5": "2.1.1",
|
||||
"json5-loader": "3.0.0",
|
||||
"jsrsasign": "8.0.12",
|
||||
@@ -198,16 +198,16 @@
|
||||
"randomcolor": "0.5.4",
|
||||
"ratelimiter": "3.4.0",
|
||||
"recaptcha-promise": "0.1.3",
|
||||
"reconnecting-websocket": "4.3.0",
|
||||
"redis": "2.8.0",
|
||||
"reconnecting-websocket": "4.4.0",
|
||||
"redis": "3.0.2",
|
||||
"redis-lock": "0.1.4",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rename": "1.0.4",
|
||||
"request": "2.88.0",
|
||||
"request": "2.88.2",
|
||||
"request-promise-native": "1.0.8",
|
||||
"request-stats": "3.0.0",
|
||||
"require-all": "3.0.0",
|
||||
"rimraf": "3.0.1",
|
||||
"rimraf": "3.0.2",
|
||||
"rndstr": "1.0.0",
|
||||
"s-age": "1.1.2",
|
||||
"sass": "1.25.0",
|
||||
@@ -221,7 +221,7 @@
|
||||
"style-loader": "1.1.3",
|
||||
"summaly": "2.3.1",
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "4.21.1",
|
||||
"systeminformation": "4.21.2",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"terser-webpack-plugin": "2.3.4",
|
||||
"textarea-caret": "3.1.0",
|
||||
@@ -245,7 +245,7 @@
|
||||
"vue-cropperjs": "4.0.1",
|
||||
"vue-i18n": "8.15.3",
|
||||
"vue-json-pretty": "1.6.3",
|
||||
"vue-loader": "15.8.3",
|
||||
"vue-loader": "15.9.0",
|
||||
"vue-marquee-text-component": "1.1.1",
|
||||
"vue-meta": "2.3.2",
|
||||
"vue-prism-component": "1.1.1",
|
||||
@@ -256,10 +256,10 @@
|
||||
"vue-template-compiler": "2.6.11",
|
||||
"vuedraggable": "2.23.2",
|
||||
"vuex": "3.1.2",
|
||||
"vuex-persistedstate": "2.7.0",
|
||||
"vuex-persistedstate": "2.7.1",
|
||||
"web-push": "3.4.3",
|
||||
"webpack": "4.41.5",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack": "4.41.6",
|
||||
"webpack-cli": "3.3.11",
|
||||
"websocket": "1.0.31",
|
||||
"ws": "7.2.1",
|
||||
"xev": "2.0.1"
|
||||
|
@@ -25,6 +25,7 @@
|
||||
<input type="search" :placeholder="$t('search')" v-model="searchQuery" v-autocomplete="{ model: 'searchQuery' }" :disabled="searchWait" @keypress="searchKeypress"/>
|
||||
</div>
|
||||
<button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>
|
||||
<x-clock v-if="isDesktop" class="clock"/>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -107,7 +108,7 @@
|
||||
|
||||
<div class="widgets">
|
||||
<div ref="widgets" :class="{ edit: widgetsEditMode }">
|
||||
<template v-if="enableWidgets && $store.getters.isSignedIn">
|
||||
<template v-if="isDesktop && $store.getters.isSignedIn">
|
||||
<template v-if="widgetsEditMode">
|
||||
<mk-button primary @click="addWidget" class="add"><fa :icon="faPlus"/></mk-button>
|
||||
<x-draggable
|
||||
@@ -166,6 +167,7 @@ export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XClock: () => import('./components/header-clock.vue').then(m => m.default),
|
||||
XNotifications: () => import('./components/notifications.vue').then(m => m.default),
|
||||
MkButton: () => import('./components/ui/button.vue').then(m => m.default),
|
||||
XDraggable: () => import('vuedraggable'),
|
||||
@@ -184,7 +186,7 @@ export default Vue.extend({
|
||||
searchQuery: '',
|
||||
searchWait: false,
|
||||
widgetsEditMode: false,
|
||||
enableWidgets: window.innerWidth >= 1100,
|
||||
isDesktop: window.innerWidth >= 1100,
|
||||
canBack: false,
|
||||
disconnectedDialog: null as Promise<void> | null,
|
||||
faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer
|
||||
@@ -273,7 +275,7 @@ export default Vue.extend({
|
||||
|
||||
mounted() {
|
||||
// https://stackoverflow.com/questions/33891709/when-flexbox-items-wrap-in-column-mode-container-does-not-grow-its-width
|
||||
if (this.enableWidgets) {
|
||||
if (this.isDesktop) {
|
||||
const adjustWidgetsWidth = () => {
|
||||
const lastChild = this.$refs.widgets.children[this.$refs.widgets.children.length - 1];
|
||||
if (lastChild == null) return;
|
||||
@@ -293,7 +295,7 @@ export default Vue.extend({
|
||||
const ro = new ResizeObserver((entries, observer) => {
|
||||
adjustTitlePosition();
|
||||
});
|
||||
|
||||
|
||||
ro.observe(this.$refs.contents);
|
||||
|
||||
window.addEventListener('resize', adjustTitlePosition);
|
||||
@@ -348,7 +350,7 @@ export default Vue.extend({
|
||||
const accountItems = accounts.map(account => ({
|
||||
type: 'user',
|
||||
user: account,
|
||||
action: () => { this.switchAccount(account) }
|
||||
action: () => { this.switchAccount(account); }
|
||||
}));
|
||||
|
||||
this.$root.menu({
|
||||
@@ -362,12 +364,28 @@ export default Vue.extend({
|
||||
text: this.$t('settings'),
|
||||
to: '/my/settings',
|
||||
icon: faCog,
|
||||
}, null, {
|
||||
}, null, ...accountItems, {
|
||||
type: 'item',
|
||||
text: this.$t('addAcount'),
|
||||
icon: faPlus,
|
||||
action: () => { this.addAcount() },
|
||||
}], ...accountItems],
|
||||
text: this.$t('addAcount'),
|
||||
action: () => {
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
type: 'item',
|
||||
text: this.$t('existingAcount'),
|
||||
action: () => { this.addAcount(); },
|
||||
}, {
|
||||
type: 'item',
|
||||
text: this.$t('createAccount'),
|
||||
action: () => { this.createAccount(); },
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 240,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
}]],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 240,
|
||||
@@ -507,9 +525,25 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
|
||||
async switchAccount(account) {
|
||||
const token = this.$store.state.device.accounts.find(x => x.id === account.id).token;
|
||||
this.$root.api('i', {}, token).then(i => {
|
||||
async createAccount() {
|
||||
this.$root.new(await import('./components/signup-dialog.vue').then(m => m.default)).$once('signup', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
this.switchAccountWithToken(res.i);
|
||||
});
|
||||
},
|
||||
|
||||
async switchAccount(account: any) {
|
||||
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
|
||||
this.switchAccountWithToken(token);
|
||||
},
|
||||
|
||||
switchAccountWithToken(token: string) {
|
||||
this.$root.dialog({
|
||||
type: 'waiting',
|
||||
iconOnly: true
|
||||
});
|
||||
|
||||
this.$root.api('i', {}, token).then((i: any) => {
|
||||
this.$store.dispatch('switchAccount', {
|
||||
...i,
|
||||
token: token
|
||||
@@ -556,6 +590,7 @@ export default Vue.extend({
|
||||
'calendar',
|
||||
'rss',
|
||||
'trends',
|
||||
'clock'
|
||||
];
|
||||
|
||||
this.$root.menu({
|
||||
@@ -753,7 +788,7 @@ export default Vue.extend({
|
||||
position: relative;
|
||||
|
||||
> input {
|
||||
width: 210px;
|
||||
width: 220px;
|
||||
box-sizing: border-box;
|
||||
margin-right: 8px;
|
||||
padding: 0 12px 0 42px;
|
||||
@@ -786,6 +821,10 @@ export default Vue.extend({
|
||||
border-radius: 100%;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
> .clock {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
BIN
src/client/assets/remove.png
Normal file
BIN
src/client/assets/remove.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 424 B |
144
src/client/components/analog-clock.vue
Normal file
144
src/client/components/analog-clock.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<svg class="mbcofsoe" viewBox="0 0 10 10" preserveAspectRatio="none">
|
||||
<circle v-for="(angle, i) in graduations"
|
||||
:cx="5 + (Math.sin(angle) * (5 - graduationsPadding))"
|
||||
:cy="5 - (Math.cos(angle) * (5 - graduationsPadding))"
|
||||
:r="i % 5 == 0 ? 0.125 : 0.05"
|
||||
:fill="i % 5 == 0 ? majorGraduationColor : minorGraduationColor"
|
||||
:key="i"/>
|
||||
|
||||
<line
|
||||
:x1="5 - (Math.sin(sAngle) * (sHandLengthRatio * handsTailLength))"
|
||||
:y1="5 + (Math.cos(sAngle) * (sHandLengthRatio * handsTailLength))"
|
||||
:x2="5 + (Math.sin(sAngle) * ((sHandLengthRatio * 5) - handsPadding))"
|
||||
:y2="5 - (Math.cos(sAngle) * ((sHandLengthRatio * 5) - handsPadding))"
|
||||
:stroke="sHandColor"
|
||||
stroke-width="0.05"/>
|
||||
|
||||
<line
|
||||
:x1="5 - (Math.sin(mAngle) * (mHandLengthRatio * handsTailLength))"
|
||||
:y1="5 + (Math.cos(mAngle) * (mHandLengthRatio * handsTailLength))"
|
||||
:x2="5 + (Math.sin(mAngle) * ((mHandLengthRatio * 5) - handsPadding))"
|
||||
:y2="5 - (Math.cos(mAngle) * ((mHandLengthRatio * 5) - handsPadding))"
|
||||
:stroke="mHandColor"
|
||||
stroke-width="0.1"/>
|
||||
|
||||
<line
|
||||
:x1="5 - (Math.sin(hAngle) * (hHandLengthRatio * handsTailLength))"
|
||||
:y1="5 + (Math.cos(hAngle) * (hHandLengthRatio * handsTailLength))"
|
||||
:x2="5 + (Math.sin(hAngle) * ((hHandLengthRatio * 5) - handsPadding))"
|
||||
:y2="5 - (Math.cos(hAngle) * ((hHandLengthRatio * 5) - handsPadding))"
|
||||
:stroke="hHandColor"
|
||||
stroke-width="0.1"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as tinycolor from 'tinycolor2';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
smooth: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
now: new Date(),
|
||||
enabled: true,
|
||||
|
||||
graduationsPadding: 0.5,
|
||||
handsPadding: 1,
|
||||
handsTailLength: 0.7,
|
||||
hHandLengthRatio: 0.75,
|
||||
mHandLengthRatio: 1,
|
||||
sHandLengthRatio: 1
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
dark(): boolean {
|
||||
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--bg')).isDark();
|
||||
},
|
||||
|
||||
majorGraduationColor(): string {
|
||||
return this.dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)';
|
||||
},
|
||||
minorGraduationColor(): string {
|
||||
return this.dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||
},
|
||||
|
||||
sHandColor(): string {
|
||||
return this.dark ? 'rgba(255, 255, 255, 0.5)' : 'rgba(0, 0, 0, 0.3)';
|
||||
},
|
||||
mHandColor(): string {
|
||||
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toHexString();
|
||||
},
|
||||
hHandColor(): string {
|
||||
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--accent')).toHexString();
|
||||
},
|
||||
|
||||
ms(): number {
|
||||
return this.now.getMilliseconds() * (this.smooth ? 1 : 0);
|
||||
},
|
||||
s(): number {
|
||||
return this.now.getSeconds();
|
||||
},
|
||||
m(): number {
|
||||
return this.now.getMinutes();
|
||||
},
|
||||
h(): number {
|
||||
return this.now.getHours();
|
||||
},
|
||||
|
||||
hAngle(): number {
|
||||
return Math.PI * (this.h % 12 + (this.m + (this.s + this.ms / 1000) / 60) / 60) / 6;
|
||||
},
|
||||
mAngle(): number {
|
||||
return Math.PI * (this.m + (this.s + this.ms / 1000) / 60) / 30;
|
||||
},
|
||||
sAngle(): number {
|
||||
return Math.PI * (this.s + this.ms / 1000) / 30;
|
||||
},
|
||||
|
||||
graduations(): any {
|
||||
const angles = [];
|
||||
for (let i = 0; i < 60; i++) {
|
||||
const angle = Math.PI * i / 30;
|
||||
angles.push(angle);
|
||||
}
|
||||
|
||||
return angles;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const update = () => {
|
||||
if (this.enabled) {
|
||||
this.tick();
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
};
|
||||
update();
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.enabled = false;
|
||||
},
|
||||
|
||||
methods: {
|
||||
tick() {
|
||||
this.now = new Date();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mbcofsoe {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="mjndxjcg _panel">
|
||||
<img src="https://xn--931a.moe/assets/error.png" alt=""/>
|
||||
<img src="https://xn--931a.moe/assets/error.png" alt="" class="_ghost"/>
|
||||
<p><fa :icon="faExclamationTriangle"/> {{ $t('error') }}</p>
|
||||
<mk-button @click="() => $emit('retry')" class="button">{{ $t('retry') }}</mk-button>
|
||||
</div>
|
||||
@@ -45,8 +45,6 @@ export default Vue.extend({
|
||||
height: 150px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 16px;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
100
src/client/components/header-clock.vue
Normal file
100
src/client/components/header-clock.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class="eqryymyo">
|
||||
<div class="header">
|
||||
<time ref="time" class="_ghost">
|
||||
<span class="yyyymmdd">{{ yyyy }}/{{ mm }}/{{ dd }}</span>
|
||||
<br>
|
||||
<span class="hhnn">{{ hh }}<span :style="{ visibility: now.getSeconds() % 2 == 0 ? 'visible' : 'hidden' }">:</span>{{ nn }}</span>
|
||||
</time>
|
||||
</div>
|
||||
<div class="content _panel">
|
||||
<mk-clock/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkClock from './analog-clock.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
MkClock
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
now: new Date(),
|
||||
clock: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
yyyy(): number {
|
||||
return this.now.getFullYear();
|
||||
},
|
||||
mm(): string {
|
||||
return ('0' + (this.now.getMonth() + 1)).slice(-2);
|
||||
},
|
||||
dd(): string {
|
||||
return ('0' + this.now.getDate()).slice(-2);
|
||||
},
|
||||
hh(): string {
|
||||
return ('0' + this.now.getHours()).slice(-2);
|
||||
},
|
||||
nn(): string {
|
||||
return ('0' + this.now.getMinutes()).slice(-2);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.tick();
|
||||
this.clock = setInterval(this.tick, 1000);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.clock);
|
||||
},
|
||||
methods: {
|
||||
tick() {
|
||||
this.now = new Date();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.eqryymyo {
|
||||
display: inline-block;
|
||||
overflow: visible;
|
||||
|
||||
> .header {
|
||||
padding: 0 12px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover + .content {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
> time {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
height: 48px;
|
||||
|
||||
> .yyyymmdd {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .content {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: auto;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
margin: 16px 0 0 0;
|
||||
padding: 16px;
|
||||
width: 230px;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -125,11 +125,13 @@ export default Vue.extend({
|
||||
|
||||
> .item {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 8px 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
font-size: 0.9em;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
@@ -82,10 +82,10 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
attrs: {
|
||||
style: `display: inline-block; font-size: 150%;`
|
||||
},
|
||||
directives: [this.$store.state.settings.disableAnimatedMfm ? {} : {
|
||||
directives: [this.$store.state.device.animatedMfm ? {
|
||||
name: 'animate-css',
|
||||
value: { classes: 'tada', iteration: 'infinite' }
|
||||
}]
|
||||
}: {}]
|
||||
}, genEl(token.children));
|
||||
}
|
||||
|
||||
@@ -110,10 +110,10 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
attrs: {
|
||||
style: 'display: inline-block;'
|
||||
},
|
||||
directives: [this.$store.state.settings.disableAnimatedMfm ? {} : {
|
||||
directives: [this.$store.state.device.animatedMfm ? {
|
||||
name: 'animate-css',
|
||||
value: { classes: 'rubberBand', iteration: 'infinite' }
|
||||
}]
|
||||
} : {}]
|
||||
}, genEl(token.children));
|
||||
}
|
||||
|
||||
@@ -122,9 +122,8 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
token.node.props.attr == 'left' ? 'reverse' :
|
||||
token.node.props.attr == 'alternate' ? 'alternate' :
|
||||
'normal';
|
||||
const style = (this.$store.state.settings.disableAnimatedMfm)
|
||||
? ''
|
||||
: `animation: spin 1.5s linear infinite; animation-direction: ${direction};`;
|
||||
const style = this.$store.state.device.animatedMfm
|
||||
? `animation: spin 1.5s linear infinite; animation-direction: ${direction};` : '';
|
||||
return (createElement as any)('span', {
|
||||
attrs: {
|
||||
style: 'display: inline-block;' + style
|
||||
@@ -135,7 +134,7 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
case 'jump': {
|
||||
return (createElement as any)('span', {
|
||||
attrs: {
|
||||
style: (this.$store.state.settings.disableAnimatedMfm) ? 'display: inline-block;' : 'display: inline-block; animation: jump 0.75s linear infinite;'
|
||||
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: jump 0.75s linear infinite;' : 'display: inline-block;'
|
||||
},
|
||||
}, genEl(token.children));
|
||||
}
|
||||
|
@@ -863,7 +863,7 @@ export default Vue.extend({
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--mkykhqkw);
|
||||
color: var(--fgHighlighted);
|
||||
}
|
||||
|
||||
> .count {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mk-notes" v-size="[{ max: 500 }]">
|
||||
<div class="empty" v-if="empty">
|
||||
<img src="https://xn--931a.moe/assets/info.png" alt=""/>
|
||||
<img src="https://xn--931a.moe/assets/info.png" alt="" class="_ghost"/>
|
||||
<div>{{ $t('noNotes') }}</div>
|
||||
</div>
|
||||
|
||||
@@ -88,8 +88,6 @@ export default Vue.extend({
|
||||
height: 128px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 16px;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<x-window @closed="() => { $emit('closed'); destroyDom(); }">
|
||||
<x-window ref="window" @closed="() => { $emit('closed'); destroyDom(); }">
|
||||
<template #header>{{ $t('signup') }}</template>
|
||||
<x-signup/>
|
||||
<x-signup :auto-set="autoSet" @signup="onSignup"/>
|
||||
</x-window>
|
||||
</template>
|
||||
|
||||
@@ -18,5 +18,20 @@ export default Vue.extend({
|
||||
XSignup,
|
||||
XWindow,
|
||||
},
|
||||
|
||||
props: {
|
||||
autoSet: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSignup(res) {
|
||||
this.$emit('signup', res);
|
||||
this.$refs.window.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@@ -84,6 +84,14 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
autoSet: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
meta() {
|
||||
return this.$store.state.instance.meta;
|
||||
@@ -97,6 +105,15 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.autoSet) {
|
||||
this.$once('signup', res => {
|
||||
localStorage.setItem('i', res.i);
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const head = document.getElementsByTagName('head')[0];
|
||||
const script = document.createElement('script');
|
||||
@@ -166,8 +183,7 @@ export default Vue.extend({
|
||||
username: this.username,
|
||||
password: this.password
|
||||
}).then(res => {
|
||||
localStorage.setItem('i', res.i);
|
||||
location.href = '/';
|
||||
this.$emit('signup', res);
|
||||
});
|
||||
}).catch(() => {
|
||||
this.submitting = false;
|
||||
|
@@ -105,7 +105,7 @@ export default Vue.extend({
|
||||
padding: 8px 14px;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
font-size: 0.9em;
|
||||
line-height: 24px;
|
||||
box-shadow: none;
|
||||
text-decoration: none;
|
||||
|
@@ -239,6 +239,10 @@ export default Vue.extend({
|
||||
position: relative;
|
||||
margin: 32px 0;
|
||||
|
||||
&:not(.inline):first-child {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@@ -77,6 +77,10 @@ export default Vue.extend({
|
||||
position: relative;
|
||||
margin: 32px 0;
|
||||
|
||||
&:not(.inline):first-child {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@@ -85,6 +85,10 @@ export default Vue.extend({
|
||||
margin: 42px 0 32px 0;
|
||||
position: relative;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@@ -42,9 +42,9 @@ export default class MiOS extends EventEmitter {
|
||||
* @param callback A function that call when initialized
|
||||
*/
|
||||
@autobind
|
||||
public async init(_callback) {
|
||||
const callback = () => {
|
||||
_callback();
|
||||
public async init(callback) {
|
||||
const finish = () => {
|
||||
callback();
|
||||
|
||||
this.store.dispatch('instance/fetch').then(() => {
|
||||
// Init service worker
|
||||
@@ -59,7 +59,7 @@ export default class MiOS extends EventEmitter {
|
||||
let me = null;
|
||||
|
||||
// Return when not signed in
|
||||
if (token == null) {
|
||||
if (token == null || token === 'null') {
|
||||
return done();
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export default class MiOS extends EventEmitter {
|
||||
this.initStream();
|
||||
|
||||
// Finish init
|
||||
callback();
|
||||
finish();
|
||||
};
|
||||
|
||||
// キャッシュがあったとき
|
||||
@@ -133,7 +133,7 @@ export default class MiOS extends EventEmitter {
|
||||
this.initStream();
|
||||
|
||||
// Finish init
|
||||
callback();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -3,9 +3,13 @@
|
||||
<portal to="icon"><fa :icon="faFileAlt"/></portal>
|
||||
<portal to="title">{{ title }}</portal>
|
||||
<main class="_card">
|
||||
<div class="_title"><fa :icon="faFileAlt"/> {{ title }}</div>
|
||||
<div class="_content">
|
||||
<div v-html="body" class="qyqbqfal"></div>
|
||||
</div>
|
||||
<div class="_footer">
|
||||
<mk-link :url="`https://github.com/syuilo/misskey/blob/master/src/docs/${doc}.ja-JP.md`" class="at">{{ $t('docSource') }}</mk-link>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
@@ -14,19 +18,27 @@
|
||||
import Vue from 'vue';
|
||||
import { faFileAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import i18n from '../i18n';
|
||||
import { url, lang } from '../config';
|
||||
import MkLink from '../components/link.vue';
|
||||
|
||||
const markdown = MarkdownIt({
|
||||
html: true
|
||||
});
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.title,
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
MkLink
|
||||
},
|
||||
|
||||
props: {
|
||||
doc: {
|
||||
type: String,
|
||||
|
@@ -62,7 +62,9 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
signup() {
|
||||
this.$root.new(XSignupDialog);
|
||||
this.$root.new(XSignupDialog, {
|
||||
autoSet: true
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -5,7 +5,7 @@
|
||||
<mk-button @click="add()" primary style="margin: 0 auto 16px auto;"><fa :icon="faPlus"/> {{ $t('add') }}</mk-button>
|
||||
<section class="_card announcements">
|
||||
<div class="_content announcement" v-for="announcement in announcements">
|
||||
<mk-input v-model="announcement.title" style="margin-top: 8px;">
|
||||
<mk-input v-model="announcement.title">
|
||||
<span>{{ $t('title') }}</span>
|
||||
</mk-input>
|
||||
<mk-textarea v-model="announcement.text">
|
||||
|
@@ -2,10 +2,10 @@
|
||||
<div class="mk-instance-emojis">
|
||||
<portal to="icon"><fa :icon="faLaugh"/></portal>
|
||||
<portal to="title">{{ $t('customEmojis') }}</portal>
|
||||
|
||||
<section class="_card local">
|
||||
<div class="_title"><fa :icon="faLaugh"/> {{ $t('customEmojis') }}</div>
|
||||
<div class="_content">
|
||||
<input ref="file" type="file" style="display: none;" @change="onChangeFile"/>
|
||||
<mk-pagination :pagination="pagination" class="emojis" ref="emojis">
|
||||
<template #empty><span>{{ $t('noCustomEmojis') }}</span></template>
|
||||
<template #default="{items}">
|
||||
@@ -13,20 +13,30 @@
|
||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||
<div class="body">
|
||||
<span class="name">{{ emoji.name }}</span>
|
||||
<span class="info">
|
||||
<b class="category">{{ emoji.category }}</b>
|
||||
<span class="aliases">{{ emoji.aliases.join(' ') }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</mk-pagination>
|
||||
</div>
|
||||
<div class="_footer">
|
||||
<mk-button inline primary @click="add()"><fa :icon="faPlus"/> {{ $t('addEmoji') }}</mk-button>
|
||||
<div class="_content" v-if="selected">
|
||||
<mk-input v-model="name"><span>{{ $t('name') }}</span></mk-input>
|
||||
<mk-input v-model="category" :datalist="categories"><span>{{ $t('category') }}</span></mk-input>
|
||||
<mk-input v-model="aliases"><span>{{ $t('tags') }}</span></mk-input>
|
||||
<mk-button inline primary @click="update"><fa :icon="faSave"/> {{ $t('save') }}</mk-button>
|
||||
<mk-button inline :disabled="selected == null" @click="del()"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</mk-button>
|
||||
</div>
|
||||
<div class="_footer">
|
||||
<mk-button inline primary @click="add"><fa :icon="faPlus"/> {{ $t('addEmoji') }}</mk-button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="_card remote">
|
||||
<div class="_title"><fa :icon="faLaugh"/> {{ $t('customEmojisOfRemote') }}</div>
|
||||
<div class="_content">
|
||||
<mk-input v-model="host" :debounce="true" style="margin-top: 0;"><span>{{ $t('host') }}</span></mk-input>
|
||||
<mk-input v-model="host" :debounce="true"><span>{{ $t('host') }}</span></mk-input>
|
||||
<mk-pagination :pagination="remotePagination" class="emojis" ref="remoteEmojis">
|
||||
<template #empty><span>{{ $t('noCustomEmojis') }}</span></template>
|
||||
<template #default="{items}">
|
||||
@@ -34,7 +44,7 @@
|
||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||
<div class="body">
|
||||
<span class="name">{{ emoji.name }}</span>
|
||||
<span class="host">{{ emoji.host }}</span>
|
||||
<span class="info">{{ emoji.host }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -49,12 +59,13 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faPlus, faSave } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faTrashAlt, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
||||
import MkButton from '../../components/ui/button.vue';
|
||||
import MkInput from '../../components/ui/input.vue';
|
||||
import MkPagination from '../../components/ui/pagination.vue';
|
||||
import { apiUrl } from '../../config';
|
||||
import { selectFile } from '../../scripts/select-file';
|
||||
import { unique } from '../../../prelude/array';
|
||||
|
||||
export default Vue.extend({
|
||||
metaInfo() {
|
||||
@@ -71,9 +82,11 @@ export default Vue.extend({
|
||||
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
selected: null,
|
||||
selectedRemote: null,
|
||||
name: null,
|
||||
category: null,
|
||||
aliases: null,
|
||||
host: '',
|
||||
pagination: {
|
||||
endpoint: 'admin/emoji/list',
|
||||
@@ -86,52 +99,48 @@ export default Vue.extend({
|
||||
host: this.host ? this.host : null
|
||||
})
|
||||
},
|
||||
faTrashAlt, faPlus, faLaugh
|
||||
faTrashAlt, faPlus, faLaugh, faSave
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
categories() {
|
||||
if (this.$store.state.instance.meta) {
|
||||
return unique(this.$store.state.instance.meta.emojis.map((x: any) => x.category || '').filter((x: string) => x !== ''));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
host() {
|
||||
this.$refs.remoteEmojis.reload();
|
||||
},
|
||||
|
||||
selected() {
|
||||
this.name = this.selected ? this.selected.name : null;
|
||||
this.category = this.selected ? this.selected.category : null;
|
||||
this.aliases = this.selected ? this.selected.aliases.join(' ') : null;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async add() {
|
||||
const { canceled: canceled, result: name } = await this.$root.dialog({
|
||||
title: this.$t('emojiName'),
|
||||
input: true
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
this.name = name;
|
||||
|
||||
(this.$refs.file as any).click();
|
||||
},
|
||||
|
||||
onChangeFile() {
|
||||
const [file] = Array.from((this.$refs.file as any).files);
|
||||
if (file == null) return;
|
||||
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
data.append('name', this.name);
|
||||
data.append('i', this.$store.state.i.token);
|
||||
async add(e) {
|
||||
const files = await selectFile(this, e.currentTarget || e.target, null, true);
|
||||
|
||||
const dialog = this.$root.dialog({
|
||||
type: 'waiting',
|
||||
text: this.$t('uploading') + '...',
|
||||
text: this.$t('doing') + '...',
|
||||
showOkButton: false,
|
||||
showCancelButton: false,
|
||||
cancelableByBgClick: false
|
||||
});
|
||||
|
||||
fetch(apiUrl + '/admin/emoji/add', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(f => {
|
||||
|
||||
Promise.all(files.map(file => this.$root.api('admin/emoji/add', {
|
||||
fileId: file.id,
|
||||
})))
|
||||
.then(() => {
|
||||
this.$refs.emojis.reload();
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
@@ -143,6 +152,22 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
|
||||
async update() {
|
||||
await this.$root.api('admin/emoji/update', {
|
||||
id: this.selected.id,
|
||||
name: this.name,
|
||||
category: this.category,
|
||||
aliases: this.aliases.split(' '),
|
||||
});
|
||||
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
iconOnly: true, autoClose: true
|
||||
});
|
||||
|
||||
this.$refs.emojis.reload();
|
||||
},
|
||||
|
||||
async del() {
|
||||
const { canceled } = await this.$root.dialog({
|
||||
type: 'warning',
|
||||
@@ -207,6 +232,18 @@ export default Vue.extend({
|
||||
> .name {
|
||||
display: block;
|
||||
}
|
||||
|
||||
> .info {
|
||||
opacity: 0.5;
|
||||
|
||||
> .category {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
> .aliases {
|
||||
font-style: oblique;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,7 +278,7 @@ export default Vue.extend({
|
||||
display: block;
|
||||
}
|
||||
|
||||
> .host {
|
||||
> .info {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<section class="_card info">
|
||||
<div class="_title"><fa :icon="faInfoCircle"/> {{ $t('basicInfo') }}</div>
|
||||
<div class="_content">
|
||||
<mk-input v-model="name" style="margin-top: 8px;">{{ $t('instanceName') }}</mk-input>
|
||||
<mk-input v-model="name">{{ $t('instanceName') }}</mk-input>
|
||||
<mk-textarea v-model="description">{{ $t('instanceDescription') }}</mk-textarea>
|
||||
<mk-input v-model="iconUrl"><template #icon><fa :icon="faLink"/></template>{{ $t('iconUrl') }}</mk-input>
|
||||
<mk-input v-model="bannerUrl"><template #icon><fa :icon="faLink"/></template>{{ $t('bannerUrl') }}</mk-input>
|
||||
@@ -78,7 +78,7 @@
|
||||
<section class="_card">
|
||||
<div class="_title"><fa :icon="faThumbtack"/> {{ $t('pinnedUsers') }}</div>
|
||||
<div class="_content">
|
||||
<mk-textarea v-model="pinnedUsers" style="margin-top: 0;">
|
||||
<mk-textarea v-model="pinnedUsers">
|
||||
<template #desc>{{ $t('pinnedUsersDescription') }} <button class="_textButton" @click="addPinUser">{{ $t('addUser') }}</button></template>
|
||||
</mk-textarea>
|
||||
</div>
|
||||
@@ -111,7 +111,7 @@
|
||||
<section class="_card">
|
||||
<div class="_title"><fa :icon="faBan"/> {{ $t('blockedInstances') }}</div>
|
||||
<div class="_content">
|
||||
<mk-textarea v-model="blockedHosts" style="margin-top: 0;">
|
||||
<mk-textarea v-model="blockedHosts">
|
||||
<template #desc>{{ $t('blockedInstancesDescription') }}</template>
|
||||
</mk-textarea>
|
||||
</div>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<section class="_card lookup">
|
||||
<div class="_title"><fa :icon="faSearch"/> {{ $t('lookup') }}</div>
|
||||
<div class="_content">
|
||||
<mk-input class="target" v-model="target" type="text" @enter="showUser()" style="margin-top: 0;">
|
||||
<mk-input class="target" v-model="target" type="text" @enter="showUser()">
|
||||
<span>{{ $t('usernameOrUserId') }}</span>
|
||||
</mk-input>
|
||||
<mk-button @click="showUser()" primary><fa :icon="faSearch"/> {{ $t('lookup') }}</mk-button>
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<div class="content">
|
||||
<div class="balloon _panel" :data-no-text="message.text == null">
|
||||
<button class="delete-button" v-if="isMe" :title="$t('delete')" @click="del">
|
||||
<img src="/assets/desktop/remove.png" alt="Delete"/>
|
||||
<img src="/assets/remove.png" alt="Delete"/>
|
||||
</button>
|
||||
<div class="content" v-if="!message.isDeleted">
|
||||
<mfm class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
|
||||
@@ -230,7 +230,7 @@ export default Vue.extend({
|
||||
> footer {
|
||||
display: block;
|
||||
margin: 2px 0 0 0;
|
||||
font-size: 10px;
|
||||
font-size: 0.65em;
|
||||
|
||||
> .read {
|
||||
margin: 0 8px;
|
||||
|
@@ -31,7 +31,10 @@
|
||||
</div>
|
||||
</router-link>
|
||||
</sequential-entrance>
|
||||
<p class="no-history" v-if="!fetching && messages.length == 0">{{ $t('no-history') }}</p>
|
||||
<div class="no-history" v-if="!fetching && messages.length == 0">
|
||||
<img src="https://xn--931a.moe/assets/info.png" alt="" class="_ghost"/>
|
||||
<div>{{ $t('noHistory') }}</div>
|
||||
</div>
|
||||
<mk-loading v-if="fetching"/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -139,6 +142,14 @@ export default Vue.extend({
|
||||
async startGroup() {
|
||||
const groups1 = await this.$root.api('users/groups/owned');
|
||||
const groups2 = await this.$root.api('users/groups/joined');
|
||||
if (groups1.length === 0 && groups2.length === 0) {
|
||||
this.$root.dialog({
|
||||
type: 'warning',
|
||||
title: this.$t('noGroups'),
|
||||
text: this.$t('joinOrCreateGroup'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const { canceled, result: group } = await this.$root.dialog({
|
||||
type: null,
|
||||
title: this.$t('group'),
|
||||
@@ -277,24 +288,18 @@ export default Vue.extend({
|
||||
}
|
||||
|
||||
> .no-history {
|
||||
margin: 0;
|
||||
padding: 2em 1em;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-weight: 500;
|
||||
|
||||
> img {
|
||||
vertical-align: bottom;
|
||||
height: 128px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
> .search {
|
||||
> .result {
|
||||
> .users {
|
||||
> li {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .history {
|
||||
> .message {
|
||||
&:not([data-is-me]):not([data-is-read]) {
|
||||
@@ -306,7 +311,7 @@ export default Vue.extend({
|
||||
|
||||
> div {
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
font-size: 0.9em;
|
||||
|
||||
> .avatar {
|
||||
margin: 0 12px 0 0;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<div class="shaynizk _card">
|
||||
<div class="_title" v-if="antenna.name">{{ antenna.name }}</div>
|
||||
<div class="_content body">
|
||||
<mk-input v-model="name" style="margin-top: 8px;">
|
||||
<mk-input v-model="name">
|
||||
<span>{{ $t('name') }}</span>
|
||||
</mk-input>
|
||||
<mk-select v-model="src">
|
||||
@@ -11,12 +11,17 @@
|
||||
<option value="home">{{ $t('_antennaSources.homeTimeline') }}</option>
|
||||
<option value="users">{{ $t('_antennaSources.users') }}</option>
|
||||
<option value="list">{{ $t('_antennaSources.userList') }}</option>
|
||||
<option value="group">{{ $t('_antennaSources.userGroup') }}</option>
|
||||
</mk-select>
|
||||
<mk-select v-model="userListId" v-if="src === 'list'">
|
||||
<template #label>{{ $t('userList') }}</template>
|
||||
<option v-for="list in userLists" :value="list.id" :key="list.id">{{ list.name }}</option>
|
||||
</mk-select>
|
||||
<mk-textarea v-model="users" v-if="src === 'users'">
|
||||
<mk-select v-model="userGroupId" v-else-if="src === 'group'">
|
||||
<template #label>{{ $t('userGroup') }}</template>
|
||||
<option v-for="group in userGroups" :value="group.id" :key="group.id">{{ group.name }}</option>
|
||||
</mk-select>
|
||||
<mk-textarea v-model="users" v-else-if="src === 'users'">
|
||||
<span>{{ $t('users') }}</span>
|
||||
<template #desc>{{ $t('antennaUsersDescription') }} <button class="_textButton" @click="addUser">{{ $t('addUser') }}</button></template>
|
||||
</mk-textarea>
|
||||
@@ -67,6 +72,7 @@ export default Vue.extend({
|
||||
name: '',
|
||||
src: '',
|
||||
userListId: null,
|
||||
userGroupId: null,
|
||||
users: '',
|
||||
keywords: '',
|
||||
caseSensitive: false,
|
||||
@@ -74,6 +80,7 @@ export default Vue.extend({
|
||||
withFile: false,
|
||||
notify: false,
|
||||
userLists: null,
|
||||
userGroups: null,
|
||||
faSave, faTrash
|
||||
};
|
||||
},
|
||||
@@ -83,6 +90,13 @@ export default Vue.extend({
|
||||
if (this.src === 'list' && this.userLists === null) {
|
||||
this.userLists = await this.$root.api('users/lists/list');
|
||||
}
|
||||
|
||||
if (this.src === 'group' && this.userGroups === null) {
|
||||
const groups1 = await this.$root.api('users/groups/owned');
|
||||
const groups2 = await this.$root.api('users/groups/joined');
|
||||
|
||||
this.userGroups = [...groups1, ...groups2];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -90,6 +104,7 @@ export default Vue.extend({
|
||||
this.name = this.antenna.name;
|
||||
this.src = this.antenna.src;
|
||||
this.userListId = this.antenna.userListId;
|
||||
this.userGroupId = this.antenna.userGroupId;
|
||||
this.users = this.antenna.users.join('\n');
|
||||
this.keywords = this.antenna.keywords.map(x => x.join(' ')).join('\n');
|
||||
this.caseSensitive = this.antenna.caseSensitive;
|
||||
@@ -105,6 +120,7 @@ export default Vue.extend({
|
||||
name: this.name,
|
||||
src: this.src,
|
||||
userListId: this.userListId,
|
||||
userGroupId: this.userGroupId,
|
||||
withReplies: this.withReplies,
|
||||
withFile: this.withFile,
|
||||
notify: this.notify,
|
||||
@@ -119,6 +135,7 @@ export default Vue.extend({
|
||||
name: this.name,
|
||||
src: this.src,
|
||||
userListId: this.userListId,
|
||||
userGroupId: this.userGroupId,
|
||||
withReplies: this.withReplies,
|
||||
withFile: this.withFile,
|
||||
notify: this.notify,
|
||||
|
@@ -50,6 +50,7 @@ export default Vue.extend({
|
||||
name: '',
|
||||
src: 'all',
|
||||
userListId: null,
|
||||
userGroupId: null,
|
||||
users: [],
|
||||
keywords: [],
|
||||
withReplies: false,
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
<section class="_card">
|
||||
<div class="_content">
|
||||
<img src="https://xn--931a.moe/assets/not-found.png" alt=""/>
|
||||
<img src="https://xn--931a.moe/assets/not-found.png" alt="" class="_ghost"/>
|
||||
<div>{{ $t('notFoundDescription') }}</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -45,8 +45,6 @@ export default Vue.extend({
|
||||
height: 150px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 16px;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
src/client/pages/settings/api.vue
Normal file
46
src/client/pages/settings/api.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<section class="_card">
|
||||
<div class="_title"><fa :icon="faKey"/> API</div>
|
||||
<div class="_content">
|
||||
<mk-input :value="$store.state.i.token" readonly>
|
||||
<span>{{ $t('token') }}</span>
|
||||
</mk-input>
|
||||
<mk-button @click="regenerateToken"><fa :icon="faSyncAlt"/> {{ $t('regenerate') }}</mk-button>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faKey, faSyncAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../../i18n';
|
||||
import MkButton from '../../components/ui/button.vue';
|
||||
import MkInput from '../../components/ui/input.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
MkButton, MkInput
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
faKey, faSyncAlt
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
regenerateToken() {
|
||||
this.$root.dialog({
|
||||
title: this.$t('password'),
|
||||
input: {
|
||||
type: 'password'
|
||||
}
|
||||
}).then(({ canceled, result: password }) => {
|
||||
if (canceled) return;
|
||||
this.$root.api('i/regenerate_token', {
|
||||
password: password
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -2,7 +2,7 @@
|
||||
<section class="_card">
|
||||
<div class="_title"><fa :icon="faCog"/> {{ $t('general') }}</div>
|
||||
<div class="_content">
|
||||
<mk-input type="file" @change="onWallpaperChange" style="margin-top: 0;">
|
||||
<mk-input type="file" @change="onWallpaperChange">
|
||||
<span>{{ $t('wallpaper') }}</span>
|
||||
<template #icon><fa :icon="faImage"/></template>
|
||||
<template #desc v-if="wallpaperUploading">{{ $t('uploading') }}<mk-ellipsis/></template>
|
||||
@@ -23,6 +23,7 @@
|
||||
<mk-button @click="readAllMessagingMessages">{{ $t('markAsReadAllTalkMessages') }}</mk-button>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<mk-switch v-model="disableAnimatedMfm">{{ $t('disableAnimatedMfm') }}</mk-switch>
|
||||
<mk-switch v-model="reduceAnimation">{{ $t('reduceUiAnimation') }}</mk-switch>
|
||||
<mk-switch v-model="useOsNativeEmojis">
|
||||
{{ $t('useOsNativeEmojis') }}
|
||||
@@ -36,6 +37,13 @@
|
||||
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
|
||||
</mk-select>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<div>{{ $t('fontSize') }}</div>
|
||||
<mk-radio v-model="fontSize" value="small"><span style="font-size: 14px;">Aa</span></mk-radio>
|
||||
<mk-radio v-model="fontSize" :value="null"><span style="font-size: 16px;">Aa</span></mk-radio>
|
||||
<mk-radio v-model="fontSize" value="large"><span style="font-size: 18px;">Aa</span></mk-radio>
|
||||
<mk-radio v-model="fontSize" value="veryLarge"><span style="font-size: 20px;">Aa</span></mk-radio>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -46,6 +54,7 @@ import MkInput from '../../components/ui/input.vue';
|
||||
import MkButton from '../../components/ui/button.vue';
|
||||
import MkSwitch from '../../components/ui/switch.vue';
|
||||
import MkSelect from '../../components/ui/select.vue';
|
||||
import MkRadio from '../../components/ui/radio.vue';
|
||||
import i18n from '../../i18n';
|
||||
import { apiUrl, langs } from '../../config';
|
||||
|
||||
@@ -57,12 +66,14 @@ export default Vue.extend({
|
||||
MkButton,
|
||||
MkSwitch,
|
||||
MkSelect,
|
||||
MkRadio,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
langs,
|
||||
lang: localStorage.getItem('lang'),
|
||||
fontSize: localStorage.getItem('fontSize'),
|
||||
wallpaperUploading: false,
|
||||
faImage, faCog
|
||||
}
|
||||
@@ -84,6 +95,11 @@ export default Vue.extend({
|
||||
set(value) { this.$store.commit('device/set', { key: 'animation', value: !value }); }
|
||||
},
|
||||
|
||||
disableAnimatedMfm: {
|
||||
get() { return !this.$store.state.device.animatedMfm; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'animatedMfm', value: !value }); }
|
||||
},
|
||||
|
||||
useOsNativeEmojis: {
|
||||
get() { return this.$store.state.device.useOsNativeEmojis; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'useOsNativeEmojis', value }); }
|
||||
@@ -95,6 +111,15 @@ export default Vue.extend({
|
||||
localStorage.setItem('lang', this.lang);
|
||||
localStorage.removeItem('locale');
|
||||
location.reload();
|
||||
},
|
||||
|
||||
fontSize() {
|
||||
if (this.fontSize == null) {
|
||||
localStorage.removeItem('fontSize');
|
||||
} else {
|
||||
localStorage.setItem('fontSize', this.fontSize);
|
||||
}
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -2,8 +2,7 @@
|
||||
<section class="_card">
|
||||
<div class="_title"><fa :icon="faBoxes"/> {{ $t('importAndExport') }}</div>
|
||||
<div class="_content">
|
||||
<input ref="file" type="file" style="display: none;" @change="onChangeFile"/>
|
||||
<mk-select v-model="exportTarget" style="margin-top: 0;">
|
||||
<mk-select v-model="exportTarget">
|
||||
<option value="notes">{{ $t('_exportOrImport.allNotes') }}</option>
|
||||
<option value="following">{{ $t('_exportOrImport.followingList') }}</option>
|
||||
<option value="user-lists">{{ $t('_exportOrImport.userLists') }}</option>
|
||||
@@ -13,6 +12,7 @@
|
||||
<mk-button inline @click="doExport()"><fa :icon="faDownload"/> {{ $t('export') }}</mk-button>
|
||||
<mk-button inline @click="doImport()" :disabled="!['following', 'user-lists'].includes(exportTarget)"><fa :icon="faUpload"/> {{ $t('import') }}</mk-button>
|
||||
</div>
|
||||
<input ref="file" type="file" style="display: none;" @change="onChangeFile"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
<x-security/>
|
||||
<x-2fa/>
|
||||
<x-integration/>
|
||||
<x-api/>
|
||||
|
||||
<mk-button @click="cacheClear()" primary class="cacheClear">{{ $t('cacheClear') }}</mk-button>
|
||||
<mk-button @click="$root.signout()" primary class="logout">{{ $t('logout') }}</mk-button>
|
||||
@@ -34,6 +35,7 @@ import XSecurity from './security.vue';
|
||||
import XTheme from './theme.vue';
|
||||
import X2fa from './2fa.vue';
|
||||
import XIntegration from './integration.vue';
|
||||
import XApi from './api.vue';
|
||||
import MkButton from '../../components/ui/button.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
@@ -55,6 +57,7 @@ export default Vue.extend({
|
||||
XTheme,
|
||||
X2fa,
|
||||
XIntegration,
|
||||
XApi,
|
||||
MkButton,
|
||||
},
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<section class="_card">
|
||||
<div class="_title"><fa :icon="faLaugh"/> {{ $t('reaction') }}</div>
|
||||
<div class="_content">
|
||||
<mk-textarea v-model="reactions" style="margin-top: 16px;">{{ $t('reaction') }}<template #desc>{{ $t('reactionSettingDescription') }}</template></mk-textarea>
|
||||
<mk-textarea v-model="reactions">{{ $t('reaction') }}<template #desc>{{ $t('reactionSettingDescription') }}</template></mk-textarea>
|
||||
</div>
|
||||
<div class="_footer">
|
||||
<mk-button @click="save()" primary inline :disabled="!changed"><fa :icon="faSave"/> {{ $t('save') }}</mk-button>
|
||||
|
@@ -380,7 +380,7 @@ export default Vue.extend({
|
||||
|
||||
> .description {
|
||||
padding: 24px 24px 24px 154px;
|
||||
font-size: 15px;
|
||||
font-size: 0.95em;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
padding: 16px;
|
||||
@@ -395,7 +395,7 @@ export default Vue.extend({
|
||||
|
||||
> .fields {
|
||||
padding: 24px;
|
||||
font-size: 14px;
|
||||
font-size: 0.9em;
|
||||
border-top: solid 1px var(--divider);
|
||||
|
||||
@media (max-width: 500px) {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { faUpload, faCloud, faLink } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faUpload, faCloud } from '@fortawesome/free-solid-svg-icons';
|
||||
import { selectDriveFile } from './select-drive-file';
|
||||
import { apiUrl } from '../config';
|
||||
|
||||
export function selectFile(component: any, src: any, label: string, multiple = false) {
|
||||
export function selectFile(component: any, src: any, label: string | null, multiple = false) {
|
||||
return new Promise((res, rej) => {
|
||||
const chooseFileFromPc = () => {
|
||||
const input = document.createElement('input');
|
||||
@@ -56,10 +56,10 @@ export function selectFile(component: any, src: any, label: string, multiple = f
|
||||
};
|
||||
|
||||
component.$root.menu({
|
||||
items: [{
|
||||
items: [label ? {
|
||||
text: label,
|
||||
type: 'label'
|
||||
}, {
|
||||
} : undefined, {
|
||||
text: component.$t('upload'),
|
||||
icon: faUpload,
|
||||
action: chooseFileFromPc
|
||||
|
@@ -38,6 +38,7 @@ const defaultDeviceSettings = {
|
||||
themes: [],
|
||||
theme: 'light',
|
||||
animation: true,
|
||||
animatedMfm: true,
|
||||
userData: {},
|
||||
};
|
||||
|
||||
|
@@ -58,6 +58,18 @@ html {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.f-small {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&.f-large {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
&.f-veryLarge {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
html.changing-theme {
|
||||
@@ -164,6 +176,19 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
._noSelect {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
|
||||
._ghost {
|
||||
&, * {
|
||||
@extend ._noSelect;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
._button {
|
||||
appearance: none;
|
||||
padding: 0;
|
||||
@@ -175,9 +200,7 @@ a {
|
||||
font-size: 1em;
|
||||
|
||||
&, * {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
@extend ._noSelect;
|
||||
}
|
||||
|
||||
* {
|
||||
|
@@ -14,6 +14,7 @@
|
||||
focus: ':alpha<0.3<@accent',
|
||||
bg: '#000',
|
||||
fg: '#c7d1d8',
|
||||
fgHighlighted: ':lighten<3<@fg',
|
||||
panel: '#111213',
|
||||
shadow: 'rgba(0, 0, 0, 0.1)',
|
||||
header: 'rgba(20, 20, 20, 0.75)',
|
||||
@@ -49,7 +50,6 @@
|
||||
pcncwizz: ':darken<2<@panel',
|
||||
vocsgcxy: 'rgba(0, 0, 0, 0.5)',
|
||||
yrnqrguo: 'rgba(255, 255, 255, 0.05)',
|
||||
mkykhqkw: ':lighten<3<@fg',
|
||||
nwjktjjq: 'rgba(255, 255, 255, 0.1)',
|
||||
geavgsxy: 'rgba(255, 255, 255, 0.05)',
|
||||
nhzhphzx: 'rgba(255, 255, 255, 0.15)',
|
||||
|
@@ -14,6 +14,7 @@
|
||||
focus: ':alpha<0.3<@accent',
|
||||
bg: '#fafafa',
|
||||
fg: '#5c6a73',
|
||||
fgHighlighted: ':darken<3<@fg',
|
||||
panel: '#fff',
|
||||
shadow: 'rgba(0, 0, 0, 0.1)',
|
||||
header: 'rgba(255, 255, 255, 0.75)',
|
||||
@@ -49,7 +50,6 @@
|
||||
pcncwizz: ':darken<2<@panel',
|
||||
vocsgcxy: 'rgba(255, 255, 255, 0.5)',
|
||||
yrnqrguo: 'rgba(0, 0, 0, 0.05)',
|
||||
mkykhqkw: ':darken<3<@fg',
|
||||
nwjktjjq: 'rgba(0, 0, 0, 0.1)',
|
||||
geavgsxy: 'rgba(0, 0, 0, 0.05)',
|
||||
nhzhphzx: 'rgba(0, 0, 0, 0.25)',
|
||||
|
@@ -132,7 +132,7 @@ export default define({
|
||||
> p {
|
||||
margin: 0;
|
||||
line-height: 18px;
|
||||
font-size: 14px;
|
||||
font-size: 0.9em;
|
||||
|
||||
> span {
|
||||
margin: 0 4px;
|
||||
@@ -142,7 +142,7 @@ export default define({
|
||||
> .day {
|
||||
margin: 10px 0;
|
||||
line-height: 32px;
|
||||
font-size: 28px;
|
||||
font-size: 1.75em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ export default define({
|
||||
|
||||
> p {
|
||||
margin: 0 0 2px 0;
|
||||
font-size: 12px;
|
||||
font-size: 0.75em;
|
||||
line-height: 18px;
|
||||
opacity: 0.8;
|
||||
|
||||
|
44
src/client/widgets/clock.vue
Normal file
44
src/client/widgets/clock.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div>
|
||||
<mk-container :naked="props.style % 2 === 0" :show-header="false">
|
||||
<div class="vubelbmv">
|
||||
<mk-analog-clock class="clock" :smooth="props.style < 2"/>
|
||||
</div>
|
||||
</mk-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from './define';
|
||||
import MkContainer from '../components/ui/container.vue';
|
||||
import MkAnalogClock from '../components/analog-clock.vue';
|
||||
|
||||
export default define({
|
||||
name: 'clock',
|
||||
props: () => ({
|
||||
style: 0
|
||||
})
|
||||
}).extend({
|
||||
components: {
|
||||
MkContainer,
|
||||
MkAnalogClock
|
||||
},
|
||||
methods: {
|
||||
func() {
|
||||
this.props.style = (this.props.style + 1) % 4;
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vubelbmv {
|
||||
padding: 8px;
|
||||
|
||||
> .clock {
|
||||
height: 150px;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -6,3 +6,4 @@ Vue.component('mkw-timeline', () => import('./timeline.vue').then(m => m.default
|
||||
Vue.component('mkw-calendar', () => import('./calendar.vue').then(m => m.default));
|
||||
Vue.component('mkw-rss', () => import('./rss.vue').then(m => m.default));
|
||||
Vue.component('mkw-trends', () => import('./trends.vue').then(m => m.default));
|
||||
Vue.component('mkw-clock', () => import('./clock.vue').then(m => m.default));
|
||||
|
@@ -4,10 +4,11 @@
|
||||
<template #header><fa :icon="faHashtag"/>{{ $t('_widgets.trends') }}</template>
|
||||
|
||||
<div class="wbrkwala">
|
||||
<transition-group tag="div" name="chart">
|
||||
<mk-loading v-if="fetching"/>
|
||||
<transition-group tag="div" name="chart" class="tags" v-else>
|
||||
<div v-for="stat in stats" :key="stat.tag">
|
||||
<div class="tag">
|
||||
<router-link :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link>
|
||||
<router-link class="a" :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link>
|
||||
<p>{{ $t('nUsersMentioned', { n: stat.usersCount }) }}</p>
|
||||
</div>
|
||||
<x-chart class="chart" :src="stat.chart"/>
|
||||
@@ -66,20 +67,10 @@ export default define({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wbrkwala {
|
||||
> .fetching,
|
||||
> .empty {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: var(--text);
|
||||
opacity: 0.7;
|
||||
height: (62px + 1px) + (62px + 1px) + (62px + 1px) + (62px + 1px) + 62px;
|
||||
overflow: hidden;
|
||||
|
||||
> [data-icon] {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
> .tags {
|
||||
.chart-move {
|
||||
transition: transform 1s ease;
|
||||
}
|
||||
@@ -96,22 +87,23 @@ export default define({
|
||||
> .tag {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
font-size: 0.9em;
|
||||
color: var(--fg);
|
||||
|
||||
> a {
|
||||
> .a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: inherit;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
> p {
|
||||
margin: 0;
|
||||
font-size: 75%;
|
||||
opacity: 0.7;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
5
src/docs/custom-emoji.ja-JP.md
Normal file
5
src/docs/custom-emoji.ja-JP.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# カスタム絵文字
|
||||
カスタム絵文字は、インスタンスで用意された画像を絵文字のように使える機能です。
|
||||
ノート、リアクション、チャット、自己紹介、名前などの場所で使うことができます。
|
||||
カスタム絵文字をそれらの場所で使うには、絵文字ピッカーボタン(ある場合)を押すか、`:`を入力して絵文字サジェストを表示します。
|
||||
テキスト内に`:foo:`のような形式の文字列が見つかると、`foo`の部分がカスタム絵文字名と解釈され、表示時には対応したカスタム絵文字に置き換わります。
|
15
src/docs/reaction.ja-JP.md
Normal file
15
src/docs/reaction.ja-JP.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# リアクション
|
||||
他の人のノートに、絵文字を付けて簡単にあなたの反応を伝えられる機能です。
|
||||
リアクションするには、ノートの + アイコンをクリックしてピッカーを表示し、絵文字を選択します。
|
||||
リアクションには[カスタム絵文字](./custom-emoji)も使用できます。
|
||||
|
||||
## リアクションピッカーのカスタマイズ
|
||||
ピッカーに表示される絵文字を自分好みにカスタマイズすることができます。
|
||||
設定の「リアクション」で設定します。
|
||||
|
||||
## リモート投稿へのリアクションについて
|
||||
リアクションはMisskeyオリジナルの機能であるため、リモートインスタンスがMisskeyでない限りは、ほとんどの場合「Like」としてアクティビティが送信されます。一般的にはLikeは「お気に入り」として実装されているようです。
|
||||
また、相手がMisskeyであったとしても、カスタム絵文字リアクションは伝わらず、自動的に「👍」等にフォールバックされます。
|
||||
|
||||
## リモートからのリアクションについて
|
||||
リモートから「Like」アクティビティを受信したとき、Misskeyでは「👍」のリアクションとして解釈されます。
|
@@ -1,9 +1,10 @@
|
||||
import { Antenna } from '../models/entities/antenna';
|
||||
import { Note } from '../models/entities/note';
|
||||
import { User } from '../models/entities/user';
|
||||
import { UserListJoinings } from '../models';
|
||||
import { UserListJoinings, UserGroupJoinings } from '../models';
|
||||
import parseAcct from './acct/parse';
|
||||
import { getFullApAccount } from './convert-host';
|
||||
import { ensure } from '../prelude/ensure';
|
||||
|
||||
export async function checkHitAntenna(antenna: Antenna, note: Note, noteUser: User, followers: User['id'][]): Promise<boolean> {
|
||||
if (note.visibility === 'specified') return false;
|
||||
@@ -22,6 +23,14 @@ export async function checkHitAntenna(antenna: Antenna, note: Note, noteUser: Us
|
||||
})).map(x => x.userId);
|
||||
|
||||
if (!listUsers.includes(note.userId)) return false;
|
||||
} else if (antenna.src === 'group') {
|
||||
const joining = await UserGroupJoinings.findOne(antenna.userGroupJoiningId!).then(ensure);
|
||||
|
||||
const groupUsers = (await UserGroupJoinings.find({
|
||||
userGroupId: joining.userGroupId
|
||||
})).map(x => x.userId);
|
||||
|
||||
if (!groupUsers.includes(note.userId)) return false;
|
||||
} else if (antenna.src === 'users') {
|
||||
const accts = antenna.users.map(x => {
|
||||
const { username, host } = parseAcct(x);
|
||||
|
@@ -2,6 +2,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
|
||||
import { User } from './user';
|
||||
import { id } from '../id';
|
||||
import { UserList } from './user-list';
|
||||
import { UserGroupJoining } from './user-group-joining';
|
||||
|
||||
@Entity()
|
||||
export class Antenna {
|
||||
@@ -32,8 +33,8 @@ export class Antenna {
|
||||
})
|
||||
public name: string;
|
||||
|
||||
@Column('enum', { enum: ['home', 'all', 'users', 'list'] })
|
||||
public src: 'home' | 'all' | 'users' | 'list';
|
||||
@Column('enum', { enum: ['home', 'all', 'users', 'list', 'group'] })
|
||||
public src: 'home' | 'all' | 'users' | 'list' | 'group';
|
||||
|
||||
@Column({
|
||||
...id(),
|
||||
@@ -47,6 +48,18 @@ export class Antenna {
|
||||
@JoinColumn()
|
||||
public userList: UserList | null;
|
||||
|
||||
@Column({
|
||||
...id(),
|
||||
nullable: true
|
||||
})
|
||||
public userGroupJoiningId: UserGroupJoining['id'] | null;
|
||||
|
||||
@ManyToOne(type => UserGroupJoining, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public userGroupJoining: UserGroupJoining | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, array: true,
|
||||
default: '{}'
|
||||
|
@@ -4,6 +4,7 @@ import { DriveFolder } from './drive-folder';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
@Index(['userId', 'folderId', 'id'])
|
||||
export class DriveFile {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
@@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
||||
import { Antenna } from '../entities/antenna';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { AntennaNotes } from '..';
|
||||
import { AntennaNotes, UserGroupJoinings } from '..';
|
||||
|
||||
export type PackedAntenna = SchemaType<typeof packedAntennaSchema>;
|
||||
|
||||
@@ -14,6 +14,7 @@ export class AntennaRepository extends Repository<Antenna> {
|
||||
const antenna = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||
|
||||
const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null;
|
||||
const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOne(antenna.userGroupJoiningId) : null;
|
||||
|
||||
return {
|
||||
id: antenna.id,
|
||||
@@ -22,6 +23,7 @@ export class AntennaRepository extends Repository<Antenna> {
|
||||
keywords: antenna.keywords,
|
||||
src: antenna.src,
|
||||
userListId: antenna.userListId,
|
||||
userGroupId: userGroupJoining ? userGroupJoining.userGroupId : null,
|
||||
users: antenna.users,
|
||||
caseSensitive: antenna.caseSensitive,
|
||||
notify: antenna.notify,
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { EntityRepository, Repository, In } from 'typeorm';
|
||||
import { Note } from '../entities/note';
|
||||
import { User } from '../entities/user';
|
||||
import { unique, concat } from '../../prelude/array';
|
||||
import { nyaize } from '../../misc/nyaize';
|
||||
import { Emojis, Users, Apps, PollVotes, DriveFiles, NoteReactions, Followings, Polls } from '..';
|
||||
import { Emojis, Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import $ from 'cafy';
|
||||
import define from '../../../define';
|
||||
import { detectUrlMime } from '../../../../../misc/detect-url-mime';
|
||||
import { Emojis } from '../../../../../models';
|
||||
import { Emojis, DriveFiles } from '../../../../../models';
|
||||
import { genId } from '../../../../../misc/gen-id';
|
||||
import { getConnection } from 'typeorm';
|
||||
import { insertModerationLog } from '../../../../../services/insert-moderation-log';
|
||||
import { ApiError } from '../../../error';
|
||||
import { ID } from '../../../../../misc/cafy-id';
|
||||
import rndstr from 'rndstr';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
@@ -18,52 +19,36 @@ export const meta = {
|
||||
requireModerator: true,
|
||||
|
||||
params: {
|
||||
name: {
|
||||
validator: $.str.min(1)
|
||||
fileId: {
|
||||
validator: $.type(ID)
|
||||
},
|
||||
|
||||
url: {
|
||||
validator: $.str.min(1)
|
||||
},
|
||||
|
||||
category: {
|
||||
validator: $.optional.str
|
||||
},
|
||||
|
||||
aliases: {
|
||||
validator: $.optional.arr($.str.min(1)),
|
||||
default: [] as string[]
|
||||
}
|
||||
},
|
||||
|
||||
errors: {
|
||||
emojiAlredyExists: {
|
||||
message: 'Emoji already exists.',
|
||||
code: 'EMOJI_ALREADY_EXISTS',
|
||||
noSuchFile: {
|
||||
message: 'No such file.',
|
||||
code: 'MO_SUCH_FILE',
|
||||
id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, me) => {
|
||||
const type = await detectUrlMime(ps.url);
|
||||
const file = await DriveFiles.findOne(ps.fileId);
|
||||
|
||||
const exists = await Emojis.findOne({
|
||||
name: ps.name,
|
||||
host: null
|
||||
});
|
||||
if (file == null) throw new ApiError(meta.errors.noSuchFile);
|
||||
|
||||
if (exists != null) throw new ApiError(meta.errors.emojiAlredyExists);
|
||||
const name = file.name.split('.')[0].match(/^[a-z0-9_]+$/) ? file.name.split('.')[0] : `_${rndstr('a-z0-9', 8)}_`;
|
||||
|
||||
const emoji = await Emojis.save({
|
||||
id: genId(),
|
||||
updatedAt: new Date(),
|
||||
name: ps.name,
|
||||
category: ps.category,
|
||||
name: name,
|
||||
category: null,
|
||||
host: null,
|
||||
aliases: ps.aliases,
|
||||
url: ps.url,
|
||||
type,
|
||||
aliases: [],
|
||||
url: file.url,
|
||||
type: file.type,
|
||||
});
|
||||
|
||||
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import $ from 'cafy';
|
||||
import define from '../../../define';
|
||||
import { detectUrlMime } from '../../../../../misc/detect-url-mime';
|
||||
import { ID } from '../../../../../misc/cafy-id';
|
||||
import { Emojis } from '../../../../../models';
|
||||
import { getConnection } from 'typeorm';
|
||||
@@ -29,10 +28,6 @@ export const meta = {
|
||||
validator: $.optional.str
|
||||
},
|
||||
|
||||
url: {
|
||||
validator: $.str
|
||||
},
|
||||
|
||||
aliases: {
|
||||
validator: $.arr($.str)
|
||||
}
|
||||
@@ -52,15 +47,11 @@ export default define(meta, async (ps) => {
|
||||
|
||||
if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji);
|
||||
|
||||
const type = await detectUrlMime(ps.url);
|
||||
|
||||
await Emojis.update(emoji.id, {
|
||||
updatedAt: new Date(),
|
||||
name: ps.name,
|
||||
category: ps.category,
|
||||
aliases: ps.aliases,
|
||||
url: ps.url,
|
||||
type,
|
||||
});
|
||||
|
||||
await getConnection().queryResultCache!.remove(['meta_emojis']);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import $ from 'cafy';
|
||||
import define from '../../define';
|
||||
import { genId } from '../../../../misc/gen-id';
|
||||
import { Antennas, UserLists } from '../../../../models';
|
||||
import { Antennas, UserLists, UserGroupJoinings } from '../../../../models';
|
||||
import { ID } from '../../../../misc/cafy-id';
|
||||
import { ApiError } from '../../error';
|
||||
|
||||
@@ -18,13 +18,17 @@ export const meta = {
|
||||
},
|
||||
|
||||
src: {
|
||||
validator: $.str.or(['home', 'all', 'users', 'list'])
|
||||
validator: $.str.or(['home', 'all', 'users', 'list', 'group'])
|
||||
},
|
||||
|
||||
userListId: {
|
||||
validator: $.nullable.optional.type(ID),
|
||||
},
|
||||
|
||||
userGroupId: {
|
||||
validator: $.nullable.optional.type(ID),
|
||||
},
|
||||
|
||||
keywords: {
|
||||
validator: $.arr($.arr($.str))
|
||||
},
|
||||
@@ -55,12 +59,19 @@ export const meta = {
|
||||
message: 'No such user list.',
|
||||
code: 'NO_SUCH_USER_LIST',
|
||||
id: '95063e93-a283-4b8b-9aa5-bcdb8df69a7f'
|
||||
},
|
||||
|
||||
noSuchUserGroup: {
|
||||
message: 'No such user group.',
|
||||
code: 'NO_SUCH_USER_GROUP',
|
||||
id: 'aa3c0b9a-8cae-47c0-92ac-202ce5906682'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user) => {
|
||||
let userList;
|
||||
let userGroupJoining;
|
||||
|
||||
if (ps.src === 'list') {
|
||||
userList = await UserLists.findOne({
|
||||
@@ -71,6 +82,15 @@ export default define(meta, async (ps, user) => {
|
||||
if (userList == null) {
|
||||
throw new ApiError(meta.errors.noSuchUserList);
|
||||
}
|
||||
} else if (ps.src === 'group') {
|
||||
userGroupJoining = await UserGroupJoinings.findOne({
|
||||
userGroupId: ps.userGroupId,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (userGroupJoining == null) {
|
||||
throw new ApiError(meta.errors.noSuchUserGroup);
|
||||
}
|
||||
}
|
||||
|
||||
const antenna = await Antennas.save({
|
||||
@@ -80,6 +100,7 @@ export default define(meta, async (ps, user) => {
|
||||
name: ps.name,
|
||||
src: ps.src,
|
||||
userListId: userList ? userList.id : null,
|
||||
userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
|
||||
keywords: ps.keywords,
|
||||
users: ps.users,
|
||||
caseSensitive: ps.caseSensitive,
|
||||
|
@@ -2,7 +2,7 @@ import $ from 'cafy';
|
||||
import { ID } from '../../../../misc/cafy-id';
|
||||
import define from '../../define';
|
||||
import { ApiError } from '../../error';
|
||||
import { Antennas, UserLists } from '../../../../models';
|
||||
import { Antennas, UserLists, UserGroupJoinings } from '../../../../models';
|
||||
|
||||
export const meta = {
|
||||
tags: ['antennas'],
|
||||
@@ -21,13 +21,17 @@ export const meta = {
|
||||
},
|
||||
|
||||
src: {
|
||||
validator: $.str.or(['home', 'all', 'users', 'list'])
|
||||
validator: $.str.or(['home', 'all', 'users', 'list', 'group'])
|
||||
},
|
||||
|
||||
userListId: {
|
||||
validator: $.nullable.optional.type(ID),
|
||||
},
|
||||
|
||||
userGroupId: {
|
||||
validator: $.nullable.optional.type(ID),
|
||||
},
|
||||
|
||||
keywords: {
|
||||
validator: $.arr($.arr($.str))
|
||||
},
|
||||
@@ -64,6 +68,12 @@ export const meta = {
|
||||
message: 'No such user list.',
|
||||
code: 'NO_SUCH_USER_LIST',
|
||||
id: '1c6b35c9-943e-48c2-81e4-2844989407f7'
|
||||
},
|
||||
|
||||
noSuchUserGroup: {
|
||||
message: 'No such user group.',
|
||||
code: 'NO_SUCH_USER_GROUP',
|
||||
id: '109ed789-b6eb-456e-b8a9-6059d567d385'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -80,6 +90,7 @@ export default define(meta, async (ps, user) => {
|
||||
}
|
||||
|
||||
let userList;
|
||||
let userGroupJoining;
|
||||
|
||||
if (ps.src === 'list') {
|
||||
userList = await UserLists.findOne({
|
||||
@@ -90,12 +101,22 @@ export default define(meta, async (ps, user) => {
|
||||
if (userList == null) {
|
||||
throw new ApiError(meta.errors.noSuchUserList);
|
||||
}
|
||||
} else if (ps.src === 'group') {
|
||||
userGroupJoining = await UserGroupJoinings.findOne({
|
||||
userGroupId: ps.userGroupId,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (userGroupJoining == null) {
|
||||
throw new ApiError(meta.errors.noSuchUserGroup);
|
||||
}
|
||||
}
|
||||
|
||||
await Antennas.update(antenna.id, {
|
||||
name: ps.name,
|
||||
src: ps.src,
|
||||
userListId: userList ? userList.id : null,
|
||||
userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
|
||||
keywords: ps.keywords,
|
||||
users: ps.users,
|
||||
caseSensitive: ps.caseSensitive,
|
||||
|
@@ -7,6 +7,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||
import { Notes } from '../../../../models';
|
||||
import { generateMuteQuery } from '../../common/generate-mute-query';
|
||||
import { activeUsersChart } from '../../../../services/chart';
|
||||
import { Brackets } from 'typeorm';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
@@ -77,6 +78,18 @@ export default define(meta, async (ps, user) => {
|
||||
ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
||||
.andWhere('note.visibility = \'public\'')
|
||||
.andWhere('note.replyId IS NULL')
|
||||
.andWhere(new Brackets(qb => { qb
|
||||
.where(`note.replyId IS NULL`) // 返信ではない
|
||||
.orWhere('note.replyUserId = :meId', { meId: user.id }) // 返信だけど自分のノートへの返信
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど自分の行った返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.userId = :meId', { meId: user.id });
|
||||
}))
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.replyUserId = note.userId', { meId: user.id });
|
||||
}));
|
||||
}))
|
||||
.leftJoinAndSelect('note.user', 'user');
|
||||
|
||||
if (user) generateMuteQuery(query, user);
|
||||
|
@@ -124,6 +124,18 @@ export default define(meta, async (ps, user) => {
|
||||
qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id })
|
||||
.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)');
|
||||
}))
|
||||
.andWhere(new Brackets(qb => { qb
|
||||
.where(`note.replyId IS NULL`) // 返信ではない
|
||||
.orWhere('note.replyUserId = :meId', { meId: user.id }) // 返信だけど自分のノートへの返信
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど自分の行った返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.userId = :meId', { meId: user.id });
|
||||
}))
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.replyUserId = note.userId', { meId: user.id });
|
||||
}));
|
||||
}))
|
||||
.leftJoinAndSelect('note.user', 'user')
|
||||
.setParameters(followingQuery.getParameters());
|
||||
|
||||
|
@@ -93,6 +93,18 @@ export default define(meta, async (ps, user) => {
|
||||
const query = makePaginationQuery(Notes.createQueryBuilder('note'),
|
||||
ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
||||
.andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)')
|
||||
.andWhere(new Brackets(qb => { qb
|
||||
.where(`note.replyId IS NULL`) // 返信ではない
|
||||
.orWhere('note.replyUserId = :meId', { meId: user.id }) // 返信だけど自分のノートへの返信
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど自分の行った返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.userId = :meId', { meId: user.id });
|
||||
}))
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.replyUserId = note.userId', { meId: user.id });
|
||||
}));
|
||||
}))
|
||||
.leftJoinAndSelect('note.user', 'user');
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
|
@@ -110,6 +110,18 @@ export default define(meta, async (ps, user) => {
|
||||
.where(`note.userId IN (${ followingQuery.getQuery() })`)
|
||||
.orWhere('note.userId = :meId', { meId: user.id });
|
||||
}))
|
||||
.andWhere(new Brackets(qb => { qb
|
||||
.where(`note.replyId IS NULL`) // 返信ではない
|
||||
.orWhere('note.replyUserId = :meId', { meId: user.id }) // 返信だけど自分のノートへの返信
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど自分の行った返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.userId = :meId', { meId: user.id });
|
||||
}))
|
||||
.orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信
|
||||
.where(`note.replyId IS NOT NULL`)
|
||||
.andWhere('note.replyUserId = note.userId', { meId: user.id });
|
||||
}));
|
||||
}))
|
||||
.leftJoinAndSelect('note.user', 'user')
|
||||
.setParameters(followingQuery.getParameters());
|
||||
|
||||
|
@@ -38,6 +38,12 @@ export default class extends Channel {
|
||||
});
|
||||
}
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply) {
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (note.reply.userId !== this.user!.id && note.userId !== this.user!.id && note.reply.userId !== note.userId) return;
|
||||
}
|
||||
|
||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
|
@@ -43,6 +43,12 @@ export default class extends Channel {
|
||||
}
|
||||
}
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply) {
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (note.reply.userId !== this.user!.id && note.userId !== this.user!.id && note.reply.userId !== note.userId) return;
|
||||
}
|
||||
|
||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
|
@@ -52,6 +52,12 @@ export default class extends Channel {
|
||||
}
|
||||
}
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply) {
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (note.reply.userId !== this.user!.id && note.userId !== this.user!.id && note.reply.userId !== note.userId) return;
|
||||
}
|
||||
|
||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
|
@@ -40,6 +40,12 @@ export default class extends Channel {
|
||||
});
|
||||
}
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply) {
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (note.reply.userId !== this.user!.id && note.userId !== this.user!.id && note.reply.userId !== note.userId) return;
|
||||
}
|
||||
|
||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
|
@@ -9,7 +9,7 @@ import { DriveFiles } from '../../models';
|
||||
import { InternalStorage } from '../../services/drive/internal-storage';
|
||||
import { downloadUrl } from '../../misc/donwload-url';
|
||||
import { detectType } from '../../misc/get-file-info';
|
||||
import { convertToJpeg, convertToPng } from '../../services/drive/image-processor';
|
||||
import { convertToJpeg, convertToPngOrJpeg } from '../../services/drive/image-processor';
|
||||
import { GenerateVideoThumbnail } from '../../services/drive/generate-video-thumbnail';
|
||||
|
||||
const assets = `${__dirname}/../../server/file/assets/`;
|
||||
@@ -59,7 +59,7 @@ export default async function(ctx: Koa.Context) {
|
||||
if (['image/jpeg', 'image/webp'].includes(mime)) {
|
||||
return await convertToJpeg(path, 498, 280);
|
||||
} else if (['image/png'].includes(mime)) {
|
||||
return await convertToPng(path, 498, 280);
|
||||
return await convertToPngOrJpeg(path, 498, 280);
|
||||
} else if (mime.startsWith('video/')) {
|
||||
return await GenerateVideoThumbnail(path);
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ app.use(views(__dirname + '/views', {
|
||||
}));
|
||||
|
||||
// Serve favicon
|
||||
app.use(favicon(`${client}/assets/favicon.png`));
|
||||
app.use(favicon(`${__dirname}/../../../assets/favicon.png`));
|
||||
|
||||
// Common request handler
|
||||
app.use(async (ctx, next) => {
|
||||
|
@@ -13,7 +13,7 @@ html
|
||||
meta(name='theme-color' content='#86b300')
|
||||
meta(property='og:site_name' content= instanceName || 'Misskey')
|
||||
meta(name='viewport' content='width=device-width, initial-scale=1')
|
||||
link(rel='icon' href= icon || '/favicon.png')
|
||||
link(rel='icon' href= icon || '/favicon.ico')
|
||||
link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png')
|
||||
link(rel='manifest' href='/manifest.json')
|
||||
|
||||
@@ -48,6 +48,11 @@ html
|
||||
}
|
||||
}
|
||||
|
||||
const fontSize = localStorage.getItem('fontSize');
|
||||
if (fontSize) {
|
||||
document.documentElement.classList.add('f-' + fontSize);
|
||||
}
|
||||
|
||||
body
|
||||
noscript: p
|
||||
| JavaScriptを有効にしてください
|
||||
|
@@ -7,7 +7,7 @@ import { deleteFile } from './delete-file';
|
||||
import { fetchMeta } from '../../misc/fetch-meta';
|
||||
import { GenerateVideoThumbnail } from './generate-video-thumbnail';
|
||||
import { driveLogger } from './logger';
|
||||
import { IImage, convertToJpeg, convertToWebp, convertToPng } from './image-processor';
|
||||
import { IImage, convertToJpeg, convertToWebp, convertToPng, convertToPngOrJpeg } from './image-processor';
|
||||
import { contentDisposition } from '../../misc/content-disposition';
|
||||
import { getFileInfo } from '../../misc/get-file-info';
|
||||
import { DriveFiles, DriveFolders, Users, Instances, UserProfiles } from '../../models';
|
||||
@@ -174,7 +174,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool
|
||||
if (['image/jpeg', 'image/webp'].includes(type)) {
|
||||
thumbnail = await convertToJpeg(path, 498, 280);
|
||||
} else if (['image/png'].includes(type)) {
|
||||
thumbnail = await convertToPng(path, 498, 280);
|
||||
thumbnail = await convertToPngOrJpeg(path, 498, 280);
|
||||
} else if (type.startsWith('video/')) {
|
||||
try {
|
||||
thumbnail = await GenerateVideoThumbnail(path);
|
||||
|
@@ -1,11 +1,17 @@
|
||||
import { DriveFile } from '../../models/entities/drive-file';
|
||||
import { InternalStorage } from './internal-storage';
|
||||
import { DriveFiles, Instances, Notes } from '../../models';
|
||||
import { DriveFiles, Instances, Notes, Users } from '../../models';
|
||||
import { driveChart, perUserDriveChart, instanceChart } from '../chart';
|
||||
import { createDeleteObjectStorageFileJob } from '../../queue';
|
||||
import { fetchMeta } from '../../misc/fetch-meta';
|
||||
import { getS3 } from './s3';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { Note } from '../../models/entities/note';
|
||||
import { renderActivity } from '../../remote/activitypub/renderer';
|
||||
import renderDelete from '../../remote/activitypub/renderer/delete';
|
||||
import renderTombstone from '../../remote/activitypub/renderer/tombstone';
|
||||
import config from '../../config';
|
||||
import { deliverToFollowers } from '../../remote/activitypub/deliver-manager';
|
||||
|
||||
export async function deleteFile(file: DriveFile, isExpired = false) {
|
||||
if (file.storedInternal) {
|
||||
@@ -63,7 +69,7 @@ export async function deleteFileSync(file: DriveFile, isExpired = false) {
|
||||
postProcess(file, isExpired);
|
||||
}
|
||||
|
||||
function postProcess(file: DriveFile, isExpired = false) {
|
||||
async function postProcess(file: DriveFile, isExpired = false) {
|
||||
// リモートファイル期限切れ削除後は直リンクにする
|
||||
if (isExpired && file.userHost !== null && file.uri != null) {
|
||||
DriveFiles.update(file.id, {
|
||||
@@ -81,8 +87,23 @@ function postProcess(file: DriveFile, isExpired = false) {
|
||||
DriveFiles.delete(file.id);
|
||||
|
||||
// TODO: トランザクション
|
||||
const relatedNotes = await findRelatedNotes(file.id);
|
||||
for (const relatedNote of relatedNotes) { // for each note with deleted driveFile
|
||||
const cascadingNotes = (await findCascadingNotes(relatedNote)).filter(note => !note.localOnly);
|
||||
for (const cascadingNote of cascadingNotes) { // for each notes subject to cascade deletion
|
||||
if (!cascadingNote.user) continue;
|
||||
if (!Users.isLocalUser(cascadingNote.user)) continue;
|
||||
const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
|
||||
deliverToFollowers(cascadingNote.user, content); // federate delete msg
|
||||
}
|
||||
if (!relatedNote.user) continue;
|
||||
if (Users.isLocalUser(relatedNote.user)) {
|
||||
const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${relatedNote.id}`), relatedNote.user));
|
||||
deliverToFollowers(relatedNote.user, content);
|
||||
}
|
||||
}
|
||||
Notes.createQueryBuilder().delete()
|
||||
.where(':id = ANY(fileIds)', { id: file.id })
|
||||
.where(':id = ANY("fileIds")', { id: file.id })
|
||||
.execute();
|
||||
}
|
||||
|
||||
@@ -106,3 +127,32 @@ export async function deleteObjectStorageFile(key: string) {
|
||||
Key: key
|
||||
}).promise();
|
||||
}
|
||||
|
||||
async function findRelatedNotes(fileId: string) {
|
||||
// NOTE: When running raw query, TypeORM converts field name to lowercase. Wrap in quotes to prevent conversion.
|
||||
const relatedNotes = await Notes.createQueryBuilder('note').where(':id = ANY("fileIds")', { id: fileId }).getMany();
|
||||
for (const relatedNote of relatedNotes) {
|
||||
const user = await Users.findOne({ id: relatedNote.userId });
|
||||
if (user)
|
||||
relatedNote.user = user;
|
||||
}
|
||||
return relatedNotes;
|
||||
}
|
||||
|
||||
async function findCascadingNotes(note: Note) {
|
||||
const cascadingNotes: Note[] = [];
|
||||
|
||||
const recursive = async (noteId: string) => {
|
||||
const query = Notes.createQueryBuilder('note')
|
||||
.where('note.replyId = :noteId', { noteId })
|
||||
.leftJoinAndSelect('note.user', 'user');
|
||||
const replies = await query.getMany();
|
||||
for (const reply of replies) {
|
||||
cascadingNotes.push(reply);
|
||||
await recursive(reply.id);
|
||||
}
|
||||
};
|
||||
await recursive(note.id);
|
||||
|
||||
return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users
|
||||
}
|
||||
|
@@ -11,7 +11,11 @@ export type IImage = {
|
||||
* with resize, remove metadata, resolve orientation, stop animation
|
||||
*/
|
||||
export async function convertToJpeg(path: string, width: number, height: number): Promise<IImage> {
|
||||
const data = await sharp(path)
|
||||
return convertSharpToJpeg(await sharp(path), width, height);
|
||||
}
|
||||
|
||||
export async function convertSharpToJpeg(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
||||
const data = await sharp
|
||||
.resize(width, height, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true
|
||||
@@ -35,7 +39,11 @@ export async function convertToJpeg(path: string, width: number, height: number)
|
||||
* with resize, remove metadata, resolve orientation, stop animation
|
||||
*/
|
||||
export async function convertToWebp(path: string, width: number, height: number): Promise<IImage> {
|
||||
const data = await sharp(path)
|
||||
return convertSharpToWebp(await sharp(path), width, height);
|
||||
}
|
||||
|
||||
export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
||||
const data = await sharp
|
||||
.resize(width, height, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true
|
||||
@@ -58,7 +66,11 @@ export async function convertToWebp(path: string, width: number, height: number)
|
||||
* with resize, remove metadata, resolve orientation, stop animation
|
||||
*/
|
||||
export async function convertToPng(path: string, width: number, height: number): Promise<IImage> {
|
||||
const data = await sharp(path)
|
||||
return convertSharpToPng(await sharp(path), width, height);
|
||||
}
|
||||
|
||||
export async function convertSharpToPng(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
||||
const data = await sharp
|
||||
.resize(width, height, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true
|
||||
@@ -73,3 +85,23 @@ export async function convertToPng(path: string, width: number, height: number):
|
||||
type: 'image/png'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to PNG or JPEG
|
||||
* with resize, remove metadata, resolve orientation, stop animation
|
||||
*/
|
||||
export async function convertToPngOrJpeg(path: string, width: number, height: number): Promise<IImage> {
|
||||
return convertSharpToPngOrJpeg(await sharp(path), width, height);
|
||||
}
|
||||
|
||||
export async function convertSharpToPngOrJpeg(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
||||
const stats = await sharp.stats();
|
||||
const metadata = await sharp.metadata();
|
||||
|
||||
// 不透明で300x300pxの範囲を超えていればJPEG
|
||||
if (stats.isOpaque && ((metadata.width && metadata.width >= 300) || (metadata.height && metadata!.height >= 300))) {
|
||||
return await convertSharpToJpeg(sharp, width, height);
|
||||
} else {
|
||||
return await convertSharpToPng(sharp, width, height);
|
||||
}
|
||||
}
|
||||
|
@@ -20,11 +20,6 @@ import { deliverToFollowers } from '../../remote/activitypub/deliver-manager';
|
||||
export default async function(user: User, note: Note, quiet = false) {
|
||||
const deletedAt = new Date();
|
||||
|
||||
await Notes.delete({
|
||||
id: note.id,
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
if (note.renoteId) {
|
||||
Notes.decrement({ id: note.renoteId }, 'renoteCount', 1);
|
||||
Notes.decrement({ id: note.renoteId }, 'score', 1);
|
||||
@@ -39,6 +34,7 @@ export default async function(user: User, note: Note, quiet = false) {
|
||||
if (Users.isLocalUser(user)) {
|
||||
let renote: Note | undefined;
|
||||
|
||||
// if deletd note is renote
|
||||
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length == 0)) {
|
||||
renote = await Notes.findOne({
|
||||
id: note.renoteId
|
||||
@@ -51,6 +47,15 @@ export default async function(user: User, note: Note, quiet = false) {
|
||||
|
||||
deliverToFollowers(user, content);
|
||||
}
|
||||
|
||||
// also deliever delete activity to cascaded notes
|
||||
const cascadingNotes = (await findCascadingNotes(note)).filter(note => !note.localOnly); // filter out local-only notes
|
||||
for (const cascadingNote of cascadingNotes) {
|
||||
if (!cascadingNote.user) continue;
|
||||
if (!Users.isLocalUser(cascadingNote.user)) continue;
|
||||
const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
|
||||
deliverToFollowers(cascadingNote.user, content);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
// 統計を更新
|
||||
@@ -64,4 +69,27 @@ export default async function(user: User, note: Note, quiet = false) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await Notes.delete({
|
||||
id: note.id,
|
||||
userId: user.id
|
||||
});
|
||||
}
|
||||
|
||||
async function findCascadingNotes(note: Note) {
|
||||
const cascadingNotes: Note[] = [];
|
||||
|
||||
const recursive = async (noteId: string) => {
|
||||
const query = Notes.createQueryBuilder('note')
|
||||
.where('note.replyId = :noteId', { noteId })
|
||||
.leftJoinAndSelect('note.user', 'user');
|
||||
const replies = await query.getMany();
|
||||
for (const reply of replies) {
|
||||
cascadingNotes.push(reply);
|
||||
await recursive(reply.id);
|
||||
}
|
||||
};
|
||||
await recursive(note.id);
|
||||
|
||||
return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users
|
||||
}
|
||||
|
329
yarn.lock
329
yarn.lock
@@ -33,10 +33,10 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@elastic/elasticsearch@7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.5.0.tgz#a54b07001e1a3912792bf9f34e6ec6a4fe0aef0c"
|
||||
integrity sha512-ahzu451ppXepQMb3Zr8eFfWn8QR7yCcUWQjU1dS4X63Ctin0GNwwSPertt4WwDkm6MnZ25o932wAEgyMFLwzdA==
|
||||
"@elastic/elasticsearch@7.6.0":
|
||||
version "7.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.6.0.tgz#960e937b56826b53d4784bc48f3375ce4efc5377"
|
||||
integrity sha512-mCS0gro7KM9fhPpRXf+X0Bxd2j688ONqhj2fibhU2E3vup6rmNgH0bw3Vuvv98D8MmFl2oCxwtv3a/Km/K8F6Q==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
decompress-response "^4.2.0"
|
||||
@@ -45,38 +45,38 @@
|
||||
once "^1.4.0"
|
||||
pump "^3.0.0"
|
||||
|
||||
"@fortawesome/fontawesome-common-types@^0.2.26":
|
||||
version "0.2.26"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.26.tgz#6e0b13a752676036f8196f8a1500d53a27b4adc1"
|
||||
integrity sha512-CcM/fIFwZlRdiWG/25xE/wHbtyUuCtqoCTrr6BsWw7hH072fR++n4L56KPydAr3ANgMJMjT8v83ZFIsDc7kE+A==
|
||||
"@fortawesome/fontawesome-common-types@^0.2.27":
|
||||
version "0.2.27"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.27.tgz#19706345859fc46adf3684ed01d11b40903b87e9"
|
||||
integrity sha512-97GaByGaXDGMkzcJX7VmR/jRJd8h1mfhtA7RsxDBN61GnWE/PPCZhOdwG/8OZYktiRUF0CvFOr+VgRkJrt6TWg==
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@1.2.26":
|
||||
version "1.2.26"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.26.tgz#671569271d6b532cdea5e3deb8ff16f8b7ac251d"
|
||||
integrity sha512-3Dfd/v2IztP1TxKOxZiB5+4kaOZK9mNy0KU1vVK7nFlPWz3gzxrCWB+AloQhQUoJ8HhGqbzjliK89Vl7PExGbw==
|
||||
"@fortawesome/fontawesome-svg-core@1.2.27":
|
||||
version "1.2.27"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.27.tgz#e4db8e3be81a40988213507c3e3d0c158a6641a3"
|
||||
integrity sha512-sOD3DKynocnHYpuw2sLPnTunDj7rLk91LYhi2axUYwuGe9cPCw7Bsu9EWtVdNJP+IYgTCZIbyARKXuy5K/nv+Q==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.26"
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.27"
|
||||
|
||||
"@fortawesome/free-brands-svg-icons@5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.12.0.tgz#b0c78627f811ac030ee0ac88df376567cf74119d"
|
||||
integrity sha512-50uCFzVUki3wfmFmrMNLFhOt8dP6YZ53zwR4dK9FR7Lwq1IVHXnSBb8MtGLe3urLJ2sA+CSu7Pc7s3i6/zLxmA==
|
||||
"@fortawesome/free-brands-svg-icons@5.12.1":
|
||||
version "5.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.12.1.tgz#67977addd15e21e57aa1ed71cd2ddecdfaa88647"
|
||||
integrity sha512-IYUYcgGsQuwiIHjRGfeSTCIQKUSZMb6FsV6mDj78K0D+YzGJkM4cvEBBUMHtnla5D2HCxncMI/9JX5YIk2GHeQ==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.26"
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.27"
|
||||
|
||||
"@fortawesome/free-regular-svg-icons@5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.12.0.tgz#9b7ed5dbd7581aab47960802cc116fdc8b6c8b7d"
|
||||
integrity sha512-FAvpmylTs0PosHwHrWPQX6/7ODc9M11kCE6AOAujFufDYzqTj2cPHT4yJO7zTEkKdAbbusJzbWpnOboMuyjeQA==
|
||||
"@fortawesome/free-regular-svg-icons@5.12.1":
|
||||
version "5.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.12.1.tgz#4b378d93655acc5e432d5ed7ee127768dd351a99"
|
||||
integrity sha512-bGda18seHXb+24K6DPUFzqn4kG7B+JViP/BscMcNUXvT00M86xNhdgP2TXSdflQXn53QWqymKjx/8rhaDOJyhA==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.26"
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.27"
|
||||
|
||||
"@fortawesome/free-solid-svg-icons@5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.12.0.tgz#8decac5844e60453cc0c7c51437d1461df053a35"
|
||||
integrity sha512-CnpsWs6GhTs9ekNB3d8rcO5HYqRkXbYKf2YNiAlTWbj5eVlPqsd/XH1F9If8jkcR1aegryAbln/qYeKVZzpM0g==
|
||||
"@fortawesome/free-solid-svg-icons@5.12.1":
|
||||
version "5.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.12.1.tgz#76b6f958a3471821ff146f8f955e6d7cfe87147c"
|
||||
integrity sha512-k3MwRFFUhyL4cuCJSaHDA0YNYMELDXX0h8JKtWYxO5XD3Dn+maXOMrVAAiNGooUyM2v/wz/TOaM0jxYVKeXX7g==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.26"
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.27"
|
||||
|
||||
"@fortawesome/vue-fontawesome@0.1.9":
|
||||
version "0.1.9"
|
||||
@@ -119,10 +119,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@koa/multer/-/multer-2.0.2.tgz#2bb5a5c5fa22329a174f6a2afb2d0710ef16a16f"
|
||||
integrity sha512-cWZUbpRNcLjLWDQ6QTWMX3ucXS+xHpJh7ngrBnsywhL7XygU5M090dDeiC9Sq1jM7IwKn9WkFZA1LyPU0q89qA==
|
||||
|
||||
"@koa/router@8.0.6":
|
||||
version "8.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.6.tgz#bd3f76e7f61450b47691ed944ce8e052b861139d"
|
||||
integrity sha512-b4BDdDks0hvLYlr20REnWpo1FmV9SVh4/GS3yvK6VQ8/zPOIYcA9x2kSJpRbLMx40nRuIV1GXkYsRT8u42jh4g==
|
||||
"@koa/router@8.0.8":
|
||||
version "8.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236"
|
||||
integrity sha512-FnT93N4NUehnXr+juupDmG2yfi0JnWdCmNEuIXpCG4TtG+9xvtrLambBH3RclycopVUOEYAim2lydiNBI7IRVg==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
http-errors "^1.7.3"
|
||||
@@ -233,6 +233,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-3.0.1.tgz#98d747a2e5e9a56070c6bf14e27bff56204e34cc"
|
||||
integrity sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==
|
||||
|
||||
"@types/debug@^4.1.5":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
|
||||
integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
|
||||
|
||||
"@types/double-ended-queue@2.1.1":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/double-ended-queue/-/double-ended-queue-2.1.1.tgz#f077386134f0f736d927812c85c43a04f21ddc27"
|
||||
@@ -440,7 +445,7 @@
|
||||
dependencies:
|
||||
"@types/koa" "*"
|
||||
|
||||
"@types/koa@*", "@types/koa@2.11.0":
|
||||
"@types/koa@*":
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.0.tgz#394a3e9ec94f796003a6c8374b4dbc2778746f20"
|
||||
integrity sha512-Hgx/1/rVlJvqYBrdeCsS7PDiR2qbxlMt1RnmNWD4Uxi5FF9nwkYqIldo7urjc+dfNpk+2NRGcnAYd4L5xEhCcQ==
|
||||
@@ -452,6 +457,18 @@
|
||||
"@types/koa-compose" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/koa@2.11.1":
|
||||
version "2.11.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.1.tgz#b116c860d61ef1e3b6a9ab0e5bb9703a69d951ff"
|
||||
integrity sha512-/kqQs+8Qd9GL0cdl39HEhK91k7xq6+Zci76RUdqtTLj1Mg1aVG7zwJm3snkeyFUeAvY8noY27eMXgqg1wHZgwA==
|
||||
dependencies:
|
||||
"@types/accepts" "*"
|
||||
"@types/cookies" "*"
|
||||
"@types/http-assert" "*"
|
||||
"@types/keygrip" "*"
|
||||
"@types/koa-compose" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/koa__cors@3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.0.1.tgz#a8cf8535f0fe682c9421f1b9379837c585f8b66b"
|
||||
@@ -505,11 +522,16 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.1.tgz#5d7ec2a789a1f77c59b7ad071b9d50bf1abbfc9e"
|
||||
integrity sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q==
|
||||
|
||||
"@types/node@*", "@types/node@13.7.0":
|
||||
"@types/node@*":
|
||||
version "13.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4"
|
||||
integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==
|
||||
|
||||
"@types/node@13.7.1":
|
||||
version "13.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.1.tgz#238eb34a66431b71d2aaddeaa7db166f25971a0d"
|
||||
integrity sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==
|
||||
|
||||
"@types/nodemailer@6.4.0":
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.0.tgz#d8c039be3ed685c4719a026455555be82c124b74"
|
||||
@@ -578,13 +600,20 @@
|
||||
dependencies:
|
||||
"@types/redis" "*"
|
||||
|
||||
"@types/redis@*", "@types/redis@2.8.14":
|
||||
"@types/redis@*":
|
||||
version "2.8.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.14.tgz#2ed46d0f923f7ccd63fbe73a46a1241e606cf716"
|
||||
integrity sha512-255dzsOLJdXFHBio9/aMHGozNkoiBUgc+g2nlNjbTSp5qcAlmpm4Z6Xs3pKOBLNIKdZbA2BkUxWvYSIwKra0Yw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/redis@2.8.15":
|
||||
version "2.8.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.15.tgz#60e178a116a2ce35b42cdd08787b40fa7fbeb3d6"
|
||||
integrity sha512-kp05OQVXH6w2vPLd86t2y4Y64jjHClbciF3w2k1MHVs5uQu/zf0HM4ibUgFGDDogBloJkTYtfjZsXjKHlMBxqw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/rename@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/rename/-/rename-1.0.1.tgz#89ef152d73f2400835c5d835c5e22d3eb6b21ba6"
|
||||
@@ -753,7 +782,7 @@
|
||||
"@types/node" "*"
|
||||
"@types/webpack" "*"
|
||||
|
||||
"@types/webpack@*", "@types/webpack@4.41.3":
|
||||
"@types/webpack@*":
|
||||
version "4.41.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.3.tgz#30c2251db1d69a45bbffd79c0577dd9baf50e7ba"
|
||||
integrity sha512-dH+BZ6pHBZFrXpnif0YU/PbmUq3lQrvRPnqkxsciSIzvG/DE+Vm/Wrjn56T7V3+B5ryQa5fw0oGnHL8tk4ll6w==
|
||||
@@ -765,6 +794,18 @@
|
||||
"@types/webpack-sources" "*"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/webpack@4.41.6":
|
||||
version "4.41.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.6.tgz#c76afbdef59159d12e3e1332dc264b75574722a2"
|
||||
integrity sha512-iWRpV5Ej+8uKrgxp6jXz3v7ZTjgtuMXY+rsxQjFNU0hYCnHkpA7vtiNffgxjuxX4feFHBbz0IF76OzX2OqDYPw==
|
||||
dependencies:
|
||||
"@types/anymatch" "*"
|
||||
"@types/node" "*"
|
||||
"@types/tapable" "*"
|
||||
"@types/uglify-js" "*"
|
||||
"@types/webpack-sources" "*"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/websocket@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.0.tgz#828c794b0a50949ad061aa311af1009934197e4b"
|
||||
@@ -779,29 +820,29 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/experimental-utils@2.18.0":
|
||||
version "2.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.18.0.tgz#e4eab839082030282496c1439bbf9fdf2a4f3da8"
|
||||
integrity sha512-J6MopKPHuJYmQUkANLip7g9I82ZLe1naCbxZZW3O2sIxTiq/9YYoOELEKY7oPg0hJ0V/AQ225h2z0Yp+RRMXhw==
|
||||
"@typescript-eslint/experimental-utils@2.19.2":
|
||||
version "2.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.19.2.tgz#4611d44cf0f0cb460c26aa7676fc0a787281e233"
|
||||
integrity sha512-B88QuwT1wMJR750YvTJBNjMZwmiPpbmKYLm1yI7PCc3x0NariqPwqaPsoJRwU9DmUi0cd9dkhz1IqEnwfD+P1A==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "2.18.0"
|
||||
"@typescript-eslint/typescript-estree" "2.19.2"
|
||||
eslint-scope "^5.0.0"
|
||||
|
||||
"@typescript-eslint/parser@2.18.0":
|
||||
version "2.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.18.0.tgz#d5f7fc1839abd4a985394e40e9d2454bd56aeb1f"
|
||||
integrity sha512-SJJPxFMEYEWkM6pGfcnjLU+NJIPo+Ko1QrCBL+i0+zV30ggLD90huEmMMhKLHBpESWy9lVEeWlQibweNQzyc+A==
|
||||
"@typescript-eslint/parser@2.19.2":
|
||||
version "2.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.19.2.tgz#21f42c0694846367e7d6a907feb08ab2f89c0879"
|
||||
integrity sha512-8uwnYGKqX9wWHGPGdLB9sk9+12sjcdqEEYKGgbS8A0IvYX59h01o8os5qXUHMq2na8vpDRaV0suTLM7S8wraTA==
|
||||
dependencies:
|
||||
"@types/eslint-visitor-keys" "^1.0.0"
|
||||
"@typescript-eslint/experimental-utils" "2.18.0"
|
||||
"@typescript-eslint/typescript-estree" "2.18.0"
|
||||
"@typescript-eslint/experimental-utils" "2.19.2"
|
||||
"@typescript-eslint/typescript-estree" "2.19.2"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@2.18.0":
|
||||
version "2.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.18.0.tgz#cfbd16ed1b111166617d718619c19b62764c8460"
|
||||
integrity sha512-gVHylf7FDb8VSi2ypFuEL3hOtoC4HkZZ5dOjXvVjoyKdRrvXAOPSzpNRnKMfaUUEiSLP8UF9j9X9EDLxC0lfZg==
|
||||
"@typescript-eslint/typescript-estree@2.19.2":
|
||||
version "2.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.19.2.tgz#67485b00172f400474d243c6c0be27581a579350"
|
||||
integrity sha512-Xu/qa0MDk6upQWqE4Qy2X16Xg8Vi32tQS2PR0AvnT/ZYS4YGDvtn2MStOh5y8Zy2mg4NuL06KUHlvCh95j9C6Q==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
@@ -1050,10 +1091,12 @@ acorn@^7.1.0:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
|
||||
integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
|
||||
|
||||
agent-base@5:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
|
||||
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
|
||||
agent-base@6:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a"
|
||||
integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==
|
||||
dependencies:
|
||||
debug "4"
|
||||
|
||||
agent-base@^4.3.0:
|
||||
version "4.3.0"
|
||||
@@ -1215,10 +1258,10 @@ anymatch@~3.1.1:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
apexcharts@3.15.3:
|
||||
version "3.15.3"
|
||||
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.15.3.tgz#e839ee30cad55c23e9bc2e80c279eae1a883c28c"
|
||||
integrity sha512-DfXhSqFaulF3C7YyMR77Jk4ESa66QjoqrBvxw3gLvRs5KK0fhmk0kuuWtxtpBulm2oWBVsi6VKHiy+YlBRPasg==
|
||||
apexcharts@3.15.6:
|
||||
version "3.15.6"
|
||||
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.15.6.tgz#1716f8badd447b06796dbcd95b5e405ec676a3bf"
|
||||
integrity sha512-8mZqg7eTZGU2zvjYUUOf+sTqgfmutipHU9lNgkqzZPtwIVGwR5PwXTBNKRJSI3AeSoQ8VZGYfzTJWoUDfGAeBw==
|
||||
dependencies:
|
||||
svg.draggable.js "^2.2.2"
|
||||
svg.easing.js "^2.0.0"
|
||||
@@ -1469,10 +1512,10 @@ autwh@0.1.0:
|
||||
dependencies:
|
||||
oauth "0.9.15"
|
||||
|
||||
aws-sdk@2.610.0:
|
||||
version "2.610.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.610.0.tgz#a8633204bed83df763095824f8110ced4a717d2a"
|
||||
integrity sha512-kqcoCTKjbxrUo2KeLQR2Jw6l4PvkbHXSDk8KqF2hXcpHibiOcMXZZPVe9X+s90RC/B2+qU95M7FImp9ByMcw7A==
|
||||
aws-sdk@2.617.0:
|
||||
version "2.617.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.617.0.tgz#aa040a75b78494dafdec9c6cce9dc0b6933e19d7"
|
||||
integrity sha512-08CVFCHdLgSqXC5kHDDyuCf62qgzJnzHcZEgSd64zM91VaQqFzGIqi/b9iTtE47JKl1UIvrj7v8g+LPrfrGULQ==
|
||||
dependencies:
|
||||
buffer "4.9.1"
|
||||
events "1.1.1"
|
||||
@@ -2453,10 +2496,10 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83"
|
||||
integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw==
|
||||
commander@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
||||
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
|
||||
|
||||
commander@^2.12.1, commander@^2.19.0, commander@^2.20.0, commander@~2.20.3:
|
||||
version "2.20.3"
|
||||
@@ -2909,7 +2952,7 @@ cssom@~0.3.6:
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
|
||||
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
|
||||
|
||||
cssstyle@^2.0.0:
|
||||
cssstyle@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992"
|
||||
integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==
|
||||
@@ -3107,7 +3150,7 @@ delegates@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
denque@^1.1.0:
|
||||
denque@^1.1.0, denque@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
|
||||
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
|
||||
@@ -3280,7 +3323,7 @@ dotenv@^6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
|
||||
integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
|
||||
|
||||
double-ended-queue@2.1.0-0, double-ended-queue@^2.1.0-0:
|
||||
double-ended-queue@2.1.0-0:
|
||||
version "2.1.0-0"
|
||||
resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
|
||||
integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=
|
||||
@@ -3860,13 +3903,13 @@ file-entry-cache@^5.0.1:
|
||||
dependencies:
|
||||
flat-cache "^2.0.1"
|
||||
|
||||
file-type@13.1.2:
|
||||
version "13.1.2"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-13.1.2.tgz#0e5b72bca7569c152e2d5a84ece07e94f77f833f"
|
||||
integrity sha512-NiHXbmclwHN38eHZfRklosbm7/W+1yacDzRCyddd0NiyuJUArQDmzJ8GPSFJGl82+I59u7sNGfcAVnJsfXJb8A==
|
||||
file-type@14.1.2:
|
||||
version "14.1.2"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-14.1.2.tgz#ee7adfa2a0483d8be3a38aea58fdf2705ab00fb4"
|
||||
integrity sha512-9NI4+QzDlEPB6OETc/FcJt8i8vNT396VweRwEwLcE07MnorWkZDopNuc+MeoYA7ArbzoK044JbaDExWys8deTQ==
|
||||
dependencies:
|
||||
readable-web-to-node-stream "^2.0.0"
|
||||
strtok3 "^5.0.2"
|
||||
strtok3 "^6.0.0"
|
||||
token-types "^2.0.0"
|
||||
typedarray-to-buffer "^3.1.5"
|
||||
|
||||
@@ -4477,7 +4520,7 @@ har-schema@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.1.0:
|
||||
har-validator@~5.1.0, har-validator@~5.1.3:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
|
||||
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
|
||||
@@ -4749,12 +4792,12 @@ https-browserify@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
https-proxy-agent@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
|
||||
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
|
||||
https-proxy-agent@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
||||
dependencies:
|
||||
agent-base "5"
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
https-proxy-agent@^3.0.0:
|
||||
@@ -5403,16 +5446,16 @@ jschardet@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184"
|
||||
integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q==
|
||||
|
||||
jsdom@16.0.1:
|
||||
version "16.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.0.1.tgz#5a5214cf69609531bf6fa5b6322fdd90ceed5bf7"
|
||||
integrity sha512-wKJe/APzq+ak9i+2ybWE20lDIhF9AkGKSZf8UsjPN39acatFB6oA7K397kQvHVikds0yQono2h6J7UjbPtPOWw==
|
||||
jsdom@16.1.0:
|
||||
version "16.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.1.0.tgz#7e245db708ee00302947be7beb88a2ffa587ad2b"
|
||||
integrity sha512-kpIcNAuZYc/L17WADOOHslz/q5+3SipP/iRb3j6zd1zQ6pFJubLi/VCdD3NqBpj/IKKK4YXny1vv44rbEUSGFg==
|
||||
dependencies:
|
||||
abab "^2.0.3"
|
||||
acorn "^7.1.0"
|
||||
acorn-globals "^4.3.2"
|
||||
cssom "^0.4.4"
|
||||
cssstyle "^2.0.0"
|
||||
cssstyle "^2.1.0"
|
||||
data-urls "^2.0.0"
|
||||
decimal.js "^10.2.0"
|
||||
domexception "^2.0.1"
|
||||
@@ -8208,12 +8251,12 @@ rechoir@^0.6.2:
|
||||
dependencies:
|
||||
resolve "^1.1.6"
|
||||
|
||||
reconnecting-websocket@4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.3.0.tgz#aaefbc7629a89450aa45324b89aec2276e728cc5"
|
||||
integrity sha512-3eaHIEVYB9Zb0GfYy1xdEHKJLA2JaawAegByZ1AZ8Npb3AiRgUN5l89cvE2H+pHTsFcoC88t32ky9qET6DJ75Q==
|
||||
reconnecting-websocket@4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
|
||||
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
|
||||
|
||||
redis-commands@1.5.0, redis-commands@^1.2.0:
|
||||
redis-commands@1.5.0, redis-commands@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785"
|
||||
integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==
|
||||
@@ -8228,11 +8271,6 @@ redis-lock@0.1.4:
|
||||
resolved "https://registry.yarnpkg.com/redis-lock/-/redis-lock-0.1.4.tgz#e83590bee22b5f01cdb65bfbd88d988045356272"
|
||||
integrity sha512-7/+zu86XVQfJVx1nHTzux5reglDiyUCDwmW7TSlvVezfhH2YLc/Rc8NE0ejQG+8/0lwKzm29/u/4+ogKeLosiA==
|
||||
|
||||
redis-parser@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b"
|
||||
integrity sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=
|
||||
|
||||
redis-parser@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
|
||||
@@ -8240,14 +8278,15 @@ redis-parser@^3.0.0:
|
||||
dependencies:
|
||||
redis-errors "^1.0.0"
|
||||
|
||||
redis@2.8.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02"
|
||||
integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==
|
||||
redis@3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/redis/-/redis-3.0.2.tgz#bd47067b8a4a3e6a2e556e57f71cc82c7360150a"
|
||||
integrity sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==
|
||||
dependencies:
|
||||
double-ended-queue "^2.1.0-0"
|
||||
redis-commands "^1.2.0"
|
||||
redis-parser "^2.6.0"
|
||||
denque "^1.4.1"
|
||||
redis-commands "^1.5.0"
|
||||
redis-errors "^1.2.0"
|
||||
redis-parser "^3.0.0"
|
||||
|
||||
reflect-metadata@0.1.13, reflect-metadata@^0.1.13:
|
||||
version "0.1.13"
|
||||
@@ -8410,6 +8449,32 @@ request@2.88.0, request@^2.73.0, request@^2.83.0, request@^2.88.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
request@2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-all@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/require-all/-/require-all-2.2.0.tgz#b4420c233ac0282d0ff49b277fb880a8b5de0894"
|
||||
@@ -8524,10 +8589,10 @@ rimraf@2.6.3:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.1.tgz#48d3d4cb46c80d388ab26cd61b1b466ae9ae225a"
|
||||
integrity sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==
|
||||
rimraf@3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
@@ -9256,12 +9321,13 @@ strip-json-comments@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
|
||||
integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
|
||||
|
||||
strtok3@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-5.0.2.tgz#bb81f1f56742e16f1a30ccce5dc3d9498aa5475a"
|
||||
integrity sha512-EFeVpFC5qDsqPEJSrIYyS/ueFBknGhgSK9cW+YAJF/cgJG/KSjoK7X6rK5xnpcLe7y1LVkVFCXWbAb+ClNKzKQ==
|
||||
strtok3@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-6.0.0.tgz#d6b900863daeacfe6c1724c6e7bb36d7a58e83c8"
|
||||
integrity sha512-ZXlmE22LZnIBvEU3n/kZGdh770fYFie65u5+2hLK9s74DoFtpkQIdBZVeYEzlolpGa+52G5IkzjUWn+iXynOEQ==
|
||||
dependencies:
|
||||
"@tokenizer/token" "^0.1.1"
|
||||
"@types/debug" "^4.1.5"
|
||||
debug "^4.1.1"
|
||||
peek-readable "^3.1.0"
|
||||
|
||||
@@ -9417,11 +9483,16 @@ syslog-pro@1.0.0:
|
||||
dependencies:
|
||||
moment "^2.22.2"
|
||||
|
||||
systeminformation@*, systeminformation@4.21.1:
|
||||
systeminformation@*:
|
||||
version "4.21.1"
|
||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.21.1.tgz#8394684676c9ca1da59d9f92458b166d9cd52cd6"
|
||||
integrity sha512-IQMy+ieSThY+MfLZaCdQsGCteMah4nhsDQcnT9DhocoJnhMKVUqDY025j1i+MSm7qdUCMXS5oV7dvttr+pSodw==
|
||||
|
||||
systeminformation@4.21.2:
|
||||
version "4.21.2"
|
||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.21.2.tgz#0ee92c0565687a5301ba141444643b43d0370ae2"
|
||||
integrity sha512-7O6laxHTstfj9MSrX77lKLfWz0zqqutWL0+uoJkR7sOOr4XCTwD0QG4shUVCiOWlVX+a8/gHJUio420FrSk8/w==
|
||||
|
||||
syuilo-password-strength@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/syuilo-password-strength/-/syuilo-password-strength-0.0.1.tgz#08f71a8f0ecb77db649f3d9a6424510d9d945f52"
|
||||
@@ -9700,7 +9771,7 @@ token-types@^2.0.0:
|
||||
"@tokenizer/token" "^0.1.0"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
tough-cookie@^2.3.3:
|
||||
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
@@ -10309,10 +10380,10 @@ vue-json-pretty@1.6.3:
|
||||
resolved "https://registry.yarnpkg.com/vue-json-pretty/-/vue-json-pretty-1.6.3.tgz#c7f378f3c9f68977047de28197735bc2cf81b15b"
|
||||
integrity sha512-dgb04fT9PMndfCI4RiQcqaV5P0hSg97LObm15Mkzjl2hL+qWJd833tOd2RhK/yk8AieZt8eJUac5NTZb31O6Mg==
|
||||
|
||||
vue-loader@15.8.3:
|
||||
version "15.8.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.8.3.tgz#857cb9e30eb5fc25e66db48dce7e4f768602a23c"
|
||||
integrity sha512-yFksTFbhp+lxlm92DrKdpVIWMpranXnTEuGSc0oW+Gk43M9LWaAmBTnfj5+FCdve715mTHvo78IdaXf5TbiTJg==
|
||||
vue-loader@15.9.0:
|
||||
version "15.9.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.0.tgz#5d4b0378a4606188fc83e587ed23c94bc3a10998"
|
||||
integrity sha512-FeDHvTSpwyLeF7LIV1PYkvqUQgTJ8UmOxhSlCyRSxaXCKk+M6NF4tDQsLsPPNeDPyR7TfRQ8MLg6v+8PsDV9xQ==
|
||||
dependencies:
|
||||
"@vue/component-compiler-utils" "^3.1.0"
|
||||
hash-sum "^1.0.2"
|
||||
@@ -10393,10 +10464,10 @@ vuedraggable@2.23.2:
|
||||
dependencies:
|
||||
sortablejs "^1.10.1"
|
||||
|
||||
vuex-persistedstate@2.7.0:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/vuex-persistedstate/-/vuex-persistedstate-2.7.0.tgz#f60aae4e1163bf293696a625526dbffaa42e429e"
|
||||
integrity sha512-mpko65DUMBY4mF4sSGsgrqjE7fwO373LFZeuNrC55glRuBBAK4dkgzjr4j4Bij7WtMoKuo2t2w0NGenjauISaQ==
|
||||
vuex-persistedstate@2.7.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/vuex-persistedstate/-/vuex-persistedstate-2.7.1.tgz#25ced829ea5789a2ed7d71a1ba057eb01a5235ad"
|
||||
integrity sha512-Ktvp6Bt6ApYj35MuxTClu+9Lpukcgl3Z/0o4PU12+Z4jU6lyOMzos0k6zGT5xrukAkGM1VV3EYNwz1TnHPhgFA==
|
||||
dependencies:
|
||||
deepmerge "^4.2.2"
|
||||
shvl "^2.0.0"
|
||||
@@ -10446,10 +10517,10 @@ webidl-conversions@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
|
||||
integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==
|
||||
|
||||
webpack-cli@3.3.10:
|
||||
version "3.3.10"
|
||||
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13"
|
||||
integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==
|
||||
webpack-cli@3.3.11:
|
||||
version "3.3.11"
|
||||
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.11.tgz#3bf21889bf597b5d82c38f215135a411edfdc631"
|
||||
integrity sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==
|
||||
dependencies:
|
||||
chalk "2.4.2"
|
||||
cross-spawn "6.0.5"
|
||||
@@ -10471,10 +10542,10 @@ webpack-sources@^1.0.1, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-
|
||||
source-list-map "^2.0.0"
|
||||
source-map "~0.6.1"
|
||||
|
||||
webpack@4.41.5:
|
||||
version "4.41.5"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c"
|
||||
integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==
|
||||
webpack@4.41.6:
|
||||
version "4.41.6"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.6.tgz#12f2f804bf6542ef166755050d4afbc8f66ba7e1"
|
||||
integrity sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA==
|
||||
dependencies:
|
||||
"@webassemblyjs/ast" "1.8.5"
|
||||
"@webassemblyjs/helper-module-context" "1.8.5"
|
||||
|
Reference in New Issue
Block a user