Compare commits

...

52 Commits

Author SHA1 Message Date
syuilo
ec222378c4 12.10.0 2020-02-15 04:32:48 +09:00
syuilo
ac930a1c6a New Crowdin translations (#5947)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)
2020-02-15 04:30:54 +09:00
syuilo
5ccd5ad56e Add driveFiles index 2020-02-15 04:29:57 +09:00
syuilo
67da90530b Use em 2020-02-15 04:02:32 +09:00
syuilo
b7f3753615 Use em 2020-02-15 03:57:43 +09:00
syuilo
d21d38509c Font size setting 2020-02-15 03:44:40 +09:00
syuilo
a59e1c0345 Use em 2020-02-15 03:25:54 +09:00
syuilo
7ab613b394 Use em 2020-02-15 03:24:09 +09:00
syuilo
c00ab0fbe2 Api key setting 2020-02-15 03:18:33 +09:00
syuilo
87451b1223 Add header clock 2020-02-15 02:54:42 +09:00
syuilo
d2b61229a3 Improve usability 2020-02-15 02:39:27 +09:00
syuilo
980584020a 🎨 2020-02-15 02:26:45 +09:00
syuilo
a43d0dafa5 🎨 2020-02-15 02:20:10 +09:00
syuilo
d5c1e7e579 Resolve #5928 2020-02-15 02:16:11 +09:00
syuilo
55bdf0d618 🎨 2020-02-15 01:40:38 +09:00
syuilo
44f7c13ad4 ✌️ 2020-02-15 01:39:14 +09:00
syuilo
7bd1a3c8ac Update CHANGELOG.md 2020-02-15 01:33:58 +09:00
Xeltica
4f1981df03 サイドバーメニューからアカウントを作成できるように (#5910)
* メニューからアカウントを作成できるようにした

* i18n

* Update signup.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2020-02-15 01:33:08 +09:00
syuilo
8689a998aa New Crowdin translations (#5938)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)
2020-02-15 01:19:53 +09:00
syuilo
079bb8d722 🎨 2020-02-15 01:18:48 +09:00
syuilo
65c0b6c7da Resolve #5939 2020-02-15 01:03:59 +09:00
syuilo
84958af4ce Improve doc page 2020-02-15 00:27:53 +09:00
syuilo
c53b59914b doc 2020-02-15 00:17:21 +09:00
syuilo
8ffd9ab2d9 Create reaction.ja-JP.md 2020-02-15 00:11:01 +09:00
syuilo
0305caf504 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-02-15 00:02:10 +09:00
syuilo
3012e4ffe0 Update CHANGELOG.md 2020-02-15 00:00:53 +09:00
MeiMei
585f3c3d3e Fix Oops! (#5945) 2020-02-14 23:59:54 +09:00
syuilo
f1d07dfbed Fix favicon provide 2020-02-14 23:55:31 +09:00
syuilo
cddfc55110 ✌️ 2020-02-14 23:55:13 +09:00
fuyu
a2ce072ae7 アナログ時計ウィジェットを移植 (#5944)
* アナログ時計ウィジェットを移植

* analog-clock -> clock
2020-02-14 23:31:24 +09:00
MeiMei
439563c5d6 サムネイルをJPEGで生成するように (#5941) 2020-02-14 11:40:45 +09:00
syuilo
962617b4f4 Update CHANGELOG.md 2020-02-14 01:28:15 +09:00
syuilo
4a202f0f7e 12.9.0 2020-02-14 01:26:28 +09:00
syuilo
6e6b12519a Refactor 2020-02-14 01:24:05 +09:00
syuilo
f5f7654f4b Improve custom emoji managemant 2020-02-14 01:09:39 +09:00
syuilo
5ac4c48ad1 動きのあるMFMを無効にするオプション 2020-02-13 23:20:12 +09:00
syuilo
7e18fd18b0 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-02-13 23:11:14 +09:00
syuilo
fb30c479ea Update CHANGELOG.md 2020-02-13 23:11:11 +09:00
DW
f40dcbfe13 Fix for CASCADE DELETE not being federated (#5812)
* Fix for CASCADE DELETE not being federated

* Use JOIN to get user

* fix typo
2020-02-13 23:08:33 +09:00
syuilo
8755b5f353 Fix bug 2020-02-13 22:48:56 +09:00
syuilo
691482bb28 Update dependencies 🚀 2020-02-13 22:39:23 +09:00
syuilo
4248bb8ce0 New Crowdin translations (#5931)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Spanish)
2020-02-13 22:35:22 +09:00
syuilo
a5653e33d3 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-02-13 22:13:35 +09:00
syuilo
072dc1c7e6 Clean up 2020-02-13 22:13:31 +09:00
syuilo
d76fceae85 Fix #5935 2020-02-13 22:13:24 +09:00
okpierre
86107b2710 Fix For Messaging Icon (#5933)
* Add icon for messaging

This will add icon within messaging

* Update messaging-room.message.vue

Link to missing icon
2020-02-13 15:53:02 +09:00
syuilo
a473768bef 🎨 2020-02-13 11:54:12 +09:00
syuilo
f7fe13a177 i18n 2020-02-13 11:46:02 +09:00
syuilo
acd29d22eb Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-02-13 11:45:02 +09:00
syuilo
c228155514 Fix #5930 2020-02-13 11:44:58 +09:00
syuilo
b601b98d5c New Crowdin translations (#5929)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Spanish)
2020-02-13 06:02:36 +09:00
syuilo
1cd3419688 Refactor 2020-02-13 05:08:01 +09:00
78 changed files with 1380 additions and 370 deletions

View File

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

View File

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

View File

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

View File

@@ -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 nimporte qui à senregistré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: "Sinscrire 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"

View File

@@ -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: "日曜日"

View File

@@ -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: "월요일"

View 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);
}
}

View 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);
}
}

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

View 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>

View File

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

View 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>

View File

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

View File

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

View File

@@ -863,7 +863,7 @@ export default Vue.extend({
}
&:hover {
color: var(--mkykhqkw);
color: var(--fgHighlighted);
}
> .count {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -62,7 +62,9 @@ export default Vue.extend({
},
signup() {
this.$root.new(XSignupDialog);
this.$root.new(XSignupDialog, {
autoSet: true
});
}
}
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,6 +50,7 @@ export default Vue.extend({
name: '',
src: 'all',
userListId: null,
userGroupId: null,
users: [],
keywords: [],
withReplies: false,

View File

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

View 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>

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

@@ -38,6 +38,7 @@ const defaultDeviceSettings = {
themes: [],
theme: 'light',
animation: true,
animatedMfm: true,
userData: {},
};

View File

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

View File

@@ -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)',

View File

@@ -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)',

View File

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

View 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>

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
# カスタム絵文字
カスタム絵文字は、インスタンスで用意された画像を絵文字のように使える機能です。
ノート、リアクション、チャット、自己紹介、名前などの場所で使うことができます。
カスタム絵文字をそれらの場所で使うには、絵文字ピッカーボタン(ある場合)を押すか、`:`を入力して絵文字サジェストを表示します。
テキスト内に`:foo:`のような形式の文字列が見つかると、`foo`の部分がカスタム絵文字名と解釈され、表示時には対応したカスタム絵文字に置き換わります。

View File

@@ -0,0 +1,15 @@
# リアクション
他の人のノートに、絵文字を付けて簡単にあなたの反応を伝えられる機能です。
リアクションするには、ノートの + アイコンをクリックしてピッカーを表示し、絵文字を選択します。
リアクションには[カスタム絵文字](./custom-emoji)も使用できます。
## リアクションピッカーのカスタマイズ
ピッカーに表示される絵文字を自分好みにカスタマイズすることができます。
設定の「リアクション」で設定します。
## リモート投稿へのリアクションについて
リアクションはMisskeyオリジナルの機能であるため、リモートインスタンスがMisskeyでない限りは、ほとんどの場合「Like」としてアクティビティが送信されます。一般的にはLikeは「お気に入り」として実装されているようです。
また、相手がMisskeyであったとしても、カスタム絵文字リアクションは伝わらず、自動的に「👍」等にフォールバックされます。
## リモートからのリアクションについて
リモートから「Like」アクティビティを受信したとき、Misskeyでは「👍」のリアクションとして解釈されます。

View File

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

View File

@@ -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: '{}'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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());

View File

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

View File

@@ -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());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) => {

View File

@@ -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を有効にしてください

View File

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

View File

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

View File

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

View File

@@ -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
View File

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