Compare commits

...

270 Commits

Author SHA1 Message Date
6edccad4dd 12.1.0 2020-02-06 17:29:59 +09:00
8fa47dbcb1 🎨 2020-02-06 17:28:45 +09:00
157f4bbc21 Update CHANGELOG.md 2020-02-06 17:26:09 +09:00
3b0d0df068 i18n 2020-02-06 17:25:04 +09:00
69802a9f00 Resolve #5850 2020-02-06 17:21:28 +09:00
b940da45af Update CHANGELOG.md 2020-02-06 17:11:46 +09:00
bd6de0e204 Fix #5848 (#5853) 2020-02-06 17:11:02 +09:00
958074e347 Update CHANGELOG.md 2020-02-06 17:08:05 +09:00
988ac80087 Correct Like id generation (#5852) 2020-02-06 17:07:37 +09:00
1c7c72181e Fix #5838 2020-02-06 17:05:19 +09:00
6857153367 Fix bug 2020-02-06 17:02:32 +09:00
0a3a0f3beb Update sequential-entrance.vue 2020-02-06 14:55:27 +09:00
e92e83746d Refactor 2020-02-06 14:37:29 +09:00
3b34b3e9ea Fix #5843 2020-02-06 14:29:36 +09:00
9506f53691 Update CHANGELOG.md 2020-02-06 14:25:36 +09:00
92dc6db134 Update CHANGELOG.md 2020-02-06 14:24:43 +09:00
1b88a7bc03 Fix #5842 and refactoring 2020-02-06 14:23:01 +09:00
781cebf194 12.0.0 2020-02-06 09:35:15 +09:00
b0c21aa233 12.0.0-beta.3 2020-02-06 09:17:30 +09:00
b58afb0414 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-02-06 09:12:32 +09:00
16b275a6b9 Update CHANGELOG.md 2020-02-06 09:12:20 +09:00
ac9612eb49 Fix nyaize 2 (#5841)
* Korean, English Nyaziation and special case exclusion

* Remove single en and unused

* order of exclude

* nl

* code style
2020-02-06 09:11:26 +09:00
416accbe78 Renoteを解除できるように
Resolve #2231
2020-02-06 09:09:24 +09:00
ee0531b048 12.0.0-beta.2 2020-02-05 21:47:04 +09:00
e80da3c865 Update CHANGELOG.md 2020-02-05 21:42:33 +09:00
712a90d502 Fix bug 2020-02-05 21:41:54 +09:00
ab995930ff Refactor 2020-02-05 21:41:49 +09:00
5dc27b6d4b Fix bug 2020-02-05 21:38:19 +09:00
391a0a1e0d Refactor 2020-02-05 21:29:41 +09:00
8d1db30129 Refactor: Better key name 2020-02-05 21:29:19 +09:00
a0f35e240f Update post-form.vue 2020-02-05 21:28:51 +09:00
570f4e921b Update CHANGELOG.md 2020-02-05 21:12:08 +09:00
ddd7b04646 korean nyaize 2020-02-05 21:11:24 +09:00
3c4bae763f Revert "Korean, English Nyaziation and special case exclusion (#5813)"
This reverts commit c110f0860e.
2020-02-05 20:56:28 +09:00
75e360ae7a 12.0.0-beta.1 2020-02-05 15:42:08 +09:00
90225f9d33 Update fetch-meta.ts 2020-02-05 15:41:14 +09:00
bb555ab8ff 🎨 2020-02-05 15:12:08 +09:00
868f6a1f0c Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-02-05 14:39:56 +09:00
a3c1a29fbf Refactor 2020-02-05 14:39:52 +09:00
f0c218200c Merge pull request #5823 from syuilo/patch/autogen/v11
[AUTOMATED] Update README.md
2020-02-05 13:37:18 +09:00
9200b1cac2 Update CHANGELOG.md 2020-02-05 11:39:46 +09:00
28c2063043 12.0.0-alpha.15 2020-02-05 10:17:30 +09:00
8818648740 プロキシアカウントをユーザー名ではなくIDで保存するように 2020-02-05 10:15:09 +09:00
ce589fee8c Fix bug 2020-02-05 09:50:03 +09:00
f86cfdb1ce Update privacy.vue 2020-02-05 09:43:55 +09:00
55cbf2c66e localOnlyを記憶できるように 2020-02-05 09:42:58 +09:00
00515d35b9 Update README.md [AUTOGEN] 2020-02-05 09:42:12 +09:00
5ce2bdf117 Fix #5799 2020-02-05 09:29:18 +09:00
e65275da95 Update post-form.vue 2020-02-05 09:21:51 +09:00
399903a462 localOnly 2020-02-05 09:15:28 +09:00
9a30314e17 Update CHANGELOG.md 2020-02-05 09:07:57 +09:00
2170a9fedb Update CHANGELOG.md 2020-02-05 09:01:27 +09:00
0c291d1d8d Fix bug nado 2020-02-05 08:59:24 +09:00
d765a43166 Update supported locales 2020-02-05 08:39:12 +09:00
45d42d1063 New Crowdin translations (#5793)
* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* 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 (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* 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 (English)

* 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 (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)
2020-02-05 08:37:11 +09:00
c5103672c9 Update CHANGELOG.md 2020-02-05 08:11:33 +09:00
8e21458e16 コンポーネントの活性時に再計算するように (#5829) 2020-02-05 07:54:49 +09:00
aade954dd7 Fix #5798 (#5816)
* Fix #5798

* clean

* Update src/client/components/post-form-attaches.vue

Co-Authored-By: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>

* nest

Co-authored-by: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>
2020-02-04 09:20:10 +09:00
3ae73555a9 Update CHANGELOG.md 2020-02-04 08:38:48 +09:00
DW
c110f0860e Korean, English Nyaziation and special case exclusion (#5813) 2020-02-04 08:30:49 +09:00
b7a4f286b0 リモート投稿にリモートでされたリアクションが表示されるように (#5817)
* 第3インスタンスへのLikeも受け入れるように

* リアクション済みだったらエラーにせずに置き換えるように

* Likeを第3インスタンスにdeliverするように

* fix

* fix

* 同じリアクションがすでにされていたら何もしない

* リモートから自身の投稿へリアクションした場合にエラーにならないように
2020-02-04 08:26:00 +09:00
f640da911b Add Unicode 12.1 Emojis (#5825)
* 絵文字ピッカーにSHIBUYA 109を追加

* Emoji regex for Unicode 12.1

* 絵文字テーブルに Unicode 12.1 分を追加
2020-02-04 08:20:51 +09:00
9e0347d3f9 Merge pull request #5815 from syuilo/patch/autogen/v11
[AUTOMATED] Update README.md
2020-02-04 00:22:47 +09:00
67496de411 AP inboxの最小リトライ間隔 1秒→1分 (#5818) 2020-02-03 21:05:38 +09:00
2a5a055d1c ページバック前に判定を追加 (#5822) 2020-02-03 21:05:13 +09:00
7075b66aa5 Update README.md [AUTOGEN] 2020-02-03 01:34:13 +09:00
93457eacf7 Merge pull request #5807 from syuilo/patch/autogen/v11
[AUTOMATED] Update README.md
2020-02-03 01:33:30 +09:00
2d1a72b218 Update CHANGELOG.md 2020-02-02 12:10:43 +09:00
DW
2db861991a Add ZWSP when federating emojis for Mastodon compatibility (#5810)
* Add ZWSP when federating emojis for Mastodon compatibility

* Use unicode escape sequence
2020-02-02 12:10:23 +09:00
DW
391500bdac Allow wider window for totp verification (#5811)
As server time and client time may not necessarily match
2020-02-02 11:50:15 +09:00
5b63c23ae1 Fix: emoji関連のリポジトリへのライセンス表記が必要 (#5809)
* .

* rename

* idx

* a
2020-02-02 06:11:14 +09:00
34a7e2888d Update README.md 2020-02-02 06:10:04 +09:00
700c343f7c Update CHANGELOG.md 2020-02-02 06:07:56 +09:00
c30960d6bf Fix hashtags contained in private notes are shown in trends (#5805)
* Update trend.ts

* Fix query

* Update create.ts

* Update create.ts

* Update trend.ts
2020-02-02 05:42:58 +09:00
ccceaabb52 Update README.md [AUTOGEN] 2020-02-02 01:05:10 +09:00
721531c5b5 Merge pull request #5795 from syuilo/patch/autogen/v11
[AUTOMATED] Update README.md
2020-02-02 01:04:42 +09:00
4f8a8f86bf Update CHANGELOG.md 2020-02-01 20:12:56 +09:00
d773c220c7 Update yarn.lock 2020-02-01 18:21:28 +09:00
b9a0d25601 Update package.json 2020-02-01 18:13:59 +09:00
6e776650be 🎨 2020-02-01 17:26:17 +09:00
cfe9452e92 Fix bug 2020-02-01 17:26:12 +09:00
03b4f19a4c Maintainerはクライアントに表示するようになった 2020-02-01 17:16:17 +09:00
a74c790ccb 12.0.0-alpha.14 2020-02-01 17:11:38 +09:00
05f9135e30 🎨 2020-02-01 17:10:56 +09:00
6f115c6d81 ")"が抜けていたので追加 (#5802) 2020-02-01 17:02:46 +09:00
f04002188d Resolve #5513 2020-02-01 16:57:12 +09:00
d00e4433ee Fix test (#5801) 2020-02-01 15:48:50 +09:00
2c1b26a988 ノートをウォッチした後にメニューが開けなくなるのを修正 (#5797) 2020-02-01 12:19:43 +09:00
ace59fa717 Fix style 2020-02-01 11:44:31 +09:00
1d1fc87920 Fix bug 2020-02-01 11:35:49 +09:00
f976f32ea9 Update .gitignore 2020-02-01 11:10:30 +09:00
cb3dd91a8c Update user.ts 2020-02-01 11:09:29 +09:00
e2610c52f3 Update router.ts 2020-02-01 10:57:47 +09:00
de239b6d67 Add note 2020-02-01 10:03:16 +09:00
149de5b17b Improve navigation 2020-02-01 09:59:55 +09:00
d47d6bb12b Fix bug 2020-02-01 09:45:30 +09:00
c30c71c338 Rename theme 2020-02-01 09:21:28 +09:00
a941c05d75 Update router.ts 2020-02-01 09:19:05 +09:00
50fd020509 Update CHANGELOG.md 2020-02-01 09:17:35 +09:00
4ec264755f Update router.ts 2020-02-01 09:16:18 +09:00
53f018aae6 Fix bug 2020-02-01 09:12:04 +09:00
38dded5061 Update avatar.vue 2020-02-01 09:01:20 +09:00
59070cd626 Keep alive index page 2020-02-01 09:00:22 +09:00
5875409841 Fix bug 2020-02-01 07:49:02 +09:00
251bf4bd61 Improve usability 2020-02-01 07:42:21 +09:00
958c59b065 Improve autocomplete 2020-02-01 07:38:40 +09:00
46b0c5f354 ✌️ 2020-02-01 07:20:17 +09:00
7ed3448e13 Resolve #1669 2020-02-01 07:16:52 +09:00
d355f3f77c Update gulpfile.ts 2020-02-01 06:32:21 +09:00
08b72eb8c7 Update README.md [AUTOGEN] 2020-01-31 18:11:11 +09:00
3f2f4fa32e Merge pull request #5786 from syuilo/patch/autogen/v11
[AUTOMATED] Update README.md
2020-01-31 18:10:58 +09:00
7fe6b1f84f Better migration 2020-01-31 16:57:13 +09:00
2cca14a625 Show patrons 2020-01-31 16:33:36 +09:00
856925f2ca Fix style 2020-01-31 15:50:46 +09:00
a774767676 Fix bug 2020-01-31 15:45:19 +09:00
299ec075e2 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-01-31 15:25:41 +09:00
17a04e2676 Update icon 2020-01-31 15:25:38 +09:00
dd3df080d3 Update CHANGELOG.md 2020-01-31 13:42:29 +09:00
960b3c0aeb Update CHANGELOG.md 2020-01-31 13:34:40 +09:00
84bf879b7d Update follow-button.vue 2020-01-31 12:01:13 +09:00
a5cf189caa Improve follow button 2020-01-31 11:58:59 +09:00
73e7c1bf67 Refactor 2020-01-31 11:38:52 +09:00
acd64f58e3 Resolve #2230 2020-01-31 11:35:18 +09:00
259254aca8 Add patreon link 2020-01-31 07:05:03 +09:00
783fa161a1 Update ja-JP.yml 2020-01-31 07:01:56 +09:00
963c7761f2 Pages 2020-01-31 07:01:45 +09:00
1d6947d321 New Crowdin translations (#5792)
* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)
2020-01-31 05:33:31 +09:00
27ffb192f0 Fix style 2020-01-31 05:21:41 +09:00
7c64d677cb Fix style 2020-01-31 05:20:10 +09:00
f1f8e6dfd3 Update CHANGELOG.md 2020-01-31 05:18:23 +09:00
635afdf53f Fix password reset 2020-01-31 05:15:59 +09:00
99b5d94b11 Show moderator badge 2020-01-31 05:09:52 +09:00
db24dddeff Make notifications widget flexible (#5791)
* Make notifications widget flexible

* fix
2020-01-31 04:53:16 +09:00
1f8334dcb7 fix 2020-01-30 20:27:14 +09:00
0252e9b4b7 Fix duplicated disconnected dialog (Fix #5782) (#5790)
* Fix #5782
fix duplicated disconnected dialog

* fix
2020-01-30 19:57:22 +09:00
13abd6596e Add some themes 🎨 2020-01-30 19:39:07 +09:00
d8ab7f158c Update CHANGELOG.md 2020-01-30 19:00:11 +09:00
5a97b67785 Fix 2020-01-30 19:00:08 +09:00
711aa564c1 AP audience (visibility) パースの修正 (#5783)
* Refactor audience

* audienceのないAP Object 対応

* fix

* Update src/remote/activitypub/audience.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/audience.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2020-01-30 18:58:13 +09:00
f6987c72ac Make timeline widget flexible (#5788) 2020-01-30 18:32:09 +09:00
9107895754 Fix bug 2020-01-30 18:31:08 +09:00
3dbc175091 Update CHANGELOG.md 2020-01-30 18:01:26 +09:00
6dee3678fe Update CHANGELOG.md 2020-01-30 17:58:53 +09:00
f55550cdeb Update CHANGELOG.md 2020-01-30 17:57:26 +09:00
1446a20c70 Update CHANGELOG.md 2020-01-30 17:44:41 +09:00
eafaebb0f9 Fix typo in CHANGELOG.md (#5789) 2020-01-30 17:31:20 +09:00
de0d7701f9 Update CHANGELOG.md 2020-01-30 17:27:21 +09:00
8e94c47362 Update CHANGELOG.md 2020-01-30 14:48:14 +09:00
48e9898db1 2fa setting 2020-01-30 13:05:14 +09:00
64dcd9d697 🎨 2020-01-30 11:12:58 +09:00
a7f337e8e4 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-01-30 11:10:48 +09:00
24c047b662 _section --> _card 2020-01-30 11:10:42 +09:00
e97bfe5696 Handle EmojiReaction activitiy (#5492)
* Handle some additional reaction activities

* Revert "Handle some additional reaction activities"

This reverts commit 1462ff12de08e8810023658e8ff7b5ee8bd7965b.

* EmojiReaction
2020-01-30 08:03:50 +09:00
fb9fed545e ✌️ 2020-01-30 07:53:19 +09:00
964bfb36d8 Improve avatar/banner setting 2020-01-30 07:13:36 +09:00
8b32157cf1 Fix bug 2020-01-30 06:23:34 +09:00
f5d5d26b0e Adjust page style 2020-01-30 06:19:18 +09:00
9f4da44b59 Fix 2020-01-30 06:11:35 +09:00
ee0cbab4e4 Fix bug 2020-01-30 06:09:36 +09:00
c44e8e6bf1 Emoji copy 2020-01-30 06:06:50 +09:00
5ceffb2c17 Add moderator switch 2020-01-30 06:00:43 +09:00
96648b651e isMarkedAsClosed --> isSuspended 2020-01-30 05:56:14 +09:00
31abd2f59b Fix bug 2020-01-30 05:45:15 +09:00
f6154dc0af v12 (#5712)
Co-authored-by: MeiMei <30769358+mei23@users.noreply.github.com>
Co-authored-by: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>
2020-01-30 04:37:25 +09:00
a5955c1123 Add Event activity-type support (#5785) 2020-01-30 01:38:05 +09:00
23f262c2e4 Add Group and Organization to validActor (#5784) 2020-01-30 01:36:44 +09:00
39640b264d Update README.md [AUTOGEN] 2020-01-30 00:01:10 +09:00
4845770880 Merge pull request #5779 from syuilo/patch/autogen/v11
[AUTOMATED] Update README.md
2020-01-30 00:00:22 +09:00
c2b6b7b179 Update README.md [AUTOGEN] 2020-01-29 00:05:06 +09:00
777c5a8704 Update README.md [AUTOGEN] (#5776) 2020-01-29 00:01:35 +09:00
467304b470 Update README.md [AUTOGEN] 2020-01-28 00:02:12 +09:00
c8ba5add8c Update README.md [AUTOGEN] (#5765) 2020-01-28 00:01:05 +09:00
bbcc09d426 Allow 'internal' device in WebAuthN (#5756) 2020-01-27 05:38:40 +09:00
01c07d120f Resolve #5762 (#5770) 2020-01-27 05:37:53 +09:00
0c1076c917 userListチャンネルのオーナーチェック Fix #5772 (#5773)
* userListチャンネルのオーナーチェック Fix #5772

* comment
2020-01-27 05:36:59 +09:00
cff91a7674 Update README.md [AUTOGEN] (#5764) 2020-01-25 22:21:28 +09:00
fa8f9c286d Update README.md [AUTOGEN] (#5763) 2020-01-25 22:15:12 +09:00
ad22491cc0 Update README.md [AUTOGEN] (#5759) 2020-01-25 21:31:54 +09:00
1fc936965c Update README.md [AUTOGEN] (#5752) 2020-01-25 20:45:07 +09:00
9c062643e1 Update README.md [AUTOGEN] (#5749) 2020-01-24 02:00:42 +09:00
f9ad250112 Update README.md [AUTOGEN] (#5747) 2020-01-24 01:59:51 +09:00
990ad0e01d Update README.md [AUTOGEN] (#5745) 2020-01-23 17:18:27 +09:00
683974fa58 Update README.md [AUTOGEN] (#5743) 2020-01-23 17:17:18 +09:00
a3eee05cea Update README.md [AUTOGEN] (#5741) 2020-01-22 07:28:27 +09:00
93dae4ec1c Update README.md [AUTOGEN] (#5740) 2020-01-22 07:27:44 +09:00
84178ba38a APの流量制限とリトライ期間の変更 (#5734)
* AP rate limit

* AP Job attempts

* fix
2020-01-20 14:14:09 +09:00
46aaf8fa9a AP Actorの鍵とkeyIdのフォーマットの変更 (#5733)
* Node PKCS#8

* keyIdを#main-key形式に
2020-01-20 04:51:44 +09:00
5a950cf991 Fix syuilo#5729 (#5732) 2020-01-20 01:53:17 +09:00
75cb7f8b36 Fix #5728 (#5731) 2020-01-20 01:52:35 +09:00
79cbf0888c Redis subscriberで認証ができないのを修正 Fix #5727 (#5730) 2020-01-20 01:51:18 +09:00
10f237be95 Add mark-admin command (#5705)
* mark-admin command

* no cli
2020-01-20 01:50:12 +09:00
85971d3d88 Fix: PagesでDRPWPMが最初のしか出てこない (#5707) 2020-01-19 03:38:59 +09:00
26b193d39d fix (#5710) 2020-01-19 03:38:22 +09:00
ab1b0cc840 Allow CORS requests in /.well-known/* routes (#5717)
* Allow CORS requests in /.well-known/* routes

* Fix bug
2020-01-16 04:46:43 +09:00
9703ba5340 ファイルと画像認識処理の改善 (#5690)
* dimensions制限とリファクタ

* comment

* 不要な変更削除

* use fromFile など

* Add probe-image-size.d.ts

* えーCRLFで作るなよ…

* Update src/@types/probe-image-size.d.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* fix d.ts

* Update src/@types/probe-image-size.d.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/@types/probe-image-size.d.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* fix

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
2020-01-12 16:40:58 +09:00
d09d06e4cb Refactor 2020-01-10 16:23:58 +09:00
3ed76718a8 Remove needless await 2020-01-10 16:04:25 +09:00
45aae00ad5 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-01-10 15:55:44 +09:00
c62a16ae64 Add some log for debugging 2020-01-10 15:55:40 +09:00
e6b93c1dbb Fix #5687 (#5701) 2020-01-10 11:16:08 +09:00
350310c4c2 ドキュメントのNode.js最小バージョンを修正 (#5700)
@typescript-eslint/parserが11.10.1以上じゃないと入らない

> error @typescript-eslint/parser@2.3.3: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "11.7.0"

https://github.com/syuilo/misskey/runs/274115939
2020-01-09 17:46:29 +09:00
1811725b9d ローカルタイムラインのテストを修正 (#5699)
visibility=specifiedな投稿はローカルタイムラインに流れない
2020-01-09 17:29:03 +09:00
c0938fe372 Update README.md [AUTOGEN] (#5698) 2020-01-09 16:50:43 +09:00
0f25c74415 カスタム絵文字リアクションでないものは絵文字クエリをしないように (#5693)
* カスタム絵文字リアクションの絵文字がNoteに添付されないのを修正

* ねんのため

* 記述順

* カスタム絵文字リアクションでないものは絵文字クエリをしないように
2020-01-09 14:37:48 +09:00
3ecb0ab161 Add GitHub Actions (#5522)
* add .github/workflows/nodejs.yml

* fix

* GitHub Actions: Node.js 8.xはサポートしない

* add .github/workflows/docker.yml

* Dockerビルドをキャッシュするように

* Run test in github actions

* 同リポジトリ内からのプルリクだと無駄に二回走るのを抑制

* 6925c00のdocker.ymlへの適応忘れ

* fix .circleci/misskey/test.yml

* test実行時にDBとかredisとか動かすように

* fix

* fix tests (#5544)

* fix test

* fix compile errors

* PATH引き継ぎでchild_process.spawn時のENOENTを修正

*  サーバー起動処理を共通化

* fix coding style

* fd=4をipcに使うように

* fix port

* fix

* fix ws port

* #4033 にテストケースを追従

* fix?

* fix??

* fix

* fix

* fix

* maybe fix

* fix

* node 10.xサポートしてなかった

* 11.10じゃないとだめだった

* fix

* remove chart test

* fix

* chart test復活

* fix

* 一回一回コネクションを閉じる

* Revert "一回一回コネクションを閉じる"

This reverts commit 56e35cf4f83070744c8dd852f1a7075011d88828.

* 一回一回sync→dropしてるのをやめてみる

* fix

* fix

* …

* キャッシュを切ってみる

* add ts to require target

* omg fix

* Revert "キャッシュを切ってみる"

This reverts commit 88161c59d2ea769ddf87143ba4fd4660a06afdf2.

* done呼び忘れ

* 実際の文字数リミットと違ってたので対応

* テストケースがバグってたので修正

* Revert "一回一回sync→dropしてるのをやめてみる"

This reverts commit a9e543ba2eef790ac7a14ae8799b898765748e35.

* fix

* fix

* fix

* fix?

* fix

* chartのconnectionを分離する

* fix

* fix

* fix tsconfig?

* Revert "fix tsconfig?"

This reverts commit ba9269eaf65507ff97ec1dd2e27260fb2cf0510b.

* fix

* TS_NODE_FILES を scripts の方で指定

* Windowsェ

* Circle CIの実行条件をmasterへのpushのみに

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2020-01-09 14:35:04 +09:00
16fb7c4557 11.37.1 2020-01-07 23:35:29 +09:00
8aafafe416 Fix #5688 (#5689)
* Resolve #5688

* あああああ

* 😇

* :thinking_face:

* Update detect-mine.ts

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2020-01-07 23:34:17 +09:00
90cfd87f46 11.37.0 2020-01-07 22:04:46 +09:00
5ff89e1538 New Crowdin translations (#5602)
* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* 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)

* 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)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Korean)

* 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 (Chinese Simplified)
2020-01-07 22:04:19 +09:00
8b6968c665 Update dependencies 🚀 2020-01-07 21:51:37 +09:00
6ef1b1b1a2 カスタム絵文字リアクションの絵文字がNoteに添付されないのを修正 (#5686)
* カスタム絵文字リアクションの絵文字がNoteに添付されないのを修正

* ねんのため

* 記述順
2020-01-07 12:28:20 +09:00
fc0e1955d7 Update README.md [AUTOGEN] (#5680) 2020-01-05 20:58:42 +09:00
c3b8123e32 Stacked bar chart の修正 (#5681)
* Revert "Stacked bar chart がおかしいのを修正 (#5654)"

This reverts commit b16e5bd136.

* apexcharts@3.12.0
2020-01-05 20:12:37 +09:00
b6ec3f655a Update README.md [AUTOGEN] (#5676) 2020-01-04 22:25:31 +09:00
e37840d870 ドライブ関連の修正 (#5673)
* ✌️

* Update add-file.ts

* fix
2020-01-04 07:20:41 +09:00
85b7eb1fb8 2020 2020-01-02 04:15:16 +09:00
541f5f1314 Hide suspended user profile (#5452) 2020-01-02 02:47:20 +09:00
a3c7901f87 Fix: リモートプロキシ時にサムネイルのContent-Typeがおかしい (#5669) 2020-01-02 02:46:13 +09:00
78ef0a9929 ドライブファイルURL生成などの修正 (#5671)
* Fix: リモートプロキシ時にサムネイルのContent-Typeがおかしい

* fix drive
2020-01-02 02:45:05 +09:00
b0bb5d8dfc 期限切れ/未保存リモートファイルのローカルプロキシ (#5655)
* Media Proxy を実装

* サンプルを追加

* https://github.com/syuilo/misskey/pull/5649#discussion_r359967471 の修正

* https://github.com/syuilo/misskey/pull/5649#discussion_r359967966 の修正

* https://github.com/syuilo/misskey/pull/5649#discussion_r359968219 の修正

* 期限切れ/未保存リモートファイルのローカルプロキシ

* 設定

* 説明

* comment out

* fix

Co-authored-by: 和風ドレッシング <37681609+CookieRamen@users.noreply.github.com>
2019-12-31 17:23:47 +09:00
307fc18138 Update README.md [AUTOGEN] (#5664) 2019-12-31 02:47:33 +09:00
330f2dedf7 Update README.md [AUTOGEN] (#5661) 2019-12-27 06:43:54 +09:00
c5c074f201 Update ja-JP.yml
誤字修正 少数→小数  
数→数値のほうがよさそうなので変更
2019-12-24 19:54:53 +09:00
b16e5bd136 Stacked bar chart がおかしいのを修正 (#5654)
* Fix stacked bar chart

* Fix drive stacked bar chart
2019-12-21 16:49:01 +09:00
e13f778b33 Update README.md [AUTOGEN] (#5647) 2019-12-20 09:48:25 +09:00
953142115c Update dependencies 🚀 2019-12-20 04:46:28 +09:00
1eb5578063 Add round function 2019-12-20 02:09:51 +09:00
9bc07c1a1c Media Proxy を実装 (#5649)
* Media Proxy を実装

* サンプルを追加
2019-12-20 01:54:28 +09:00
cbbdc98744 /files/ 下のヘッダ設定タイミングを修正 (#5650) 2019-12-20 01:39:59 +09:00
4229065a69 Update README.md [AUTOGEN] (#5643) 2019-12-17 04:43:31 +09:00
932436096f 管理画面でstatsを継続リクエストしないように (#5608) 2019-12-15 03:43:31 +09:00
d95242cab0 ミュート/ブロックでページングと解除ができるように (#5610) 2019-12-15 03:42:33 +09:00
4214a0618e Update showdown to 1.9.1 (#5615) 2019-12-15 03:41:18 +09:00
c012f4f880 AP引用でquoteUrlに対応 (#5632)
* Supports quoteUrl

* Quote resolveをリトライする

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
2019-12-15 03:37:54 +09:00
3e85aad80a Implement Talk has read federation (#5636)
* Talk read

* fix

* 複数のRead ActivityはCollectionとして送るように

* あ
2019-12-15 03:37:19 +09:00
648be3005f Fix #5637 (#5638) 2019-12-15 03:35:09 +09:00
66165b1935 Redis prefixにホスト名を使用するように (Resolve #5639) (#5640) 2019-12-15 03:34:11 +09:00
e9360ac892 Fix AP inbox Announce (#5641) 2019-12-15 03:32:48 +09:00
1d234e10bd Fix #4800 (#5622) 2019-12-12 00:49:30 +09:00
2a9de356db Fix #5611 (#5612) 2019-12-12 00:46:10 +09:00
43f3f8a058 Resolve syuilo#5548 (#5607) 2019-12-12 00:41:26 +09:00
4998ba8866 Fix #5424 (#5604) 2019-12-12 00:39:59 +09:00
d18291cf0c gulpのminifyプロセスの改善 (#5624)
* Use terser instead of uglify

* Use gulp-clean-css instead of gulp-cssnano

* isProduction分岐を削除
2019-12-12 00:37:58 +09:00
fe9371f06c AP Signatureヘッダの特殊処理を削除 (#5628) 2019-12-11 23:14:51 +09:00
05a15afadb Update README.md [AUTOGEN] (#5634) 2019-12-11 21:57:49 +09:00
93417912bb Update README.md [AUTOGEN] (#5631) 2019-12-10 21:40:42 +09:00
07a565a61a Update README.md [AUTOGEN] (#5626) 2019-12-10 21:25:36 +09:00
332b13dfd0 Update README.md [AUTOGEN] (#5618) 2019-12-03 08:53:08 +09:00
81477ea7ee Update README.md [AUTOGEN] (#5613) 2019-12-02 15:43:06 +09:00
39e84539cd Update README.md [AUTOGEN] (#5606) 2019-12-01 17:39:30 +09:00
6496fbf923 Update README.md [AUTOGEN] (#5601) 2019-11-25 18:27:00 +09:00
de57dd7c97 11.36.0 2019-11-24 17:12:05 +09:00
9985c010bc Update master.ts 2019-11-24 17:11:53 +09:00
f7a328d66e Update dependencies 🚀 2019-11-24 17:09:32 +09:00
50598bcefb New Crowdin translations (#5573)
* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Polish)
2019-11-24 17:01:34 +09:00
9c38e9722a Fix bug 2019-11-24 16:43:19 +09:00
b241967fb9 Fix: ローカルにフォロワー限定投稿が流れてくる (#5598) 2019-11-24 08:31:57 +09:00
1f86a6d329 Fix bug 2019-11-23 09:43:47 +09:00
7a6b5b0bfc Remove unused import 2019-11-18 06:30:58 +09:00
e406791b7b Fix bug 2019-11-18 06:27:22 +09:00
4ce2f596ee Refactor 2019-11-18 06:25:47 +09:00
567f71fe61 Refactor 2019-11-18 06:23:44 +09:00
70bb5879f9 boot: remove setAttribute() calls and translate reload msg (#5532)
* boot: remove setAttribute() calls and translate reload msg

* Update src/client/app/boot.js

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
2019-11-17 00:44:21 +09:00
cfd2d84b14 Link joinmisskey 2019-11-17 00:15:48 +09:00
44ab428803 無駄なAP deliverをしないように (#5589)
* DeliverManager, note/create

* recipe

* followers delivers

* comment

* rename

* fix

* cleanup
2019-11-09 18:51:54 +09:00
b34b728fbb Resolve #5587 (#5588)
* Resolve #5587

* stat
2019-11-09 18:24:41 +09:00
8ada1725bf 管理画面のジョブキュー一覧の修正 (#5586)
* Fix: inboxのジョブキューが表示されない

* ジョブキューで試行回数等を表示するように

* DBとオブジェクトストレージのジョブキューが表示されるように
2019-11-07 05:41:44 +09:00
873444c3c6 APの統計とログの修正と強化 (#5585)
* Fix #5580

* Improve AP logging
2019-11-07 00:02:18 +09:00
8bdd4fd061 Resolve #5582 (#5583) 2019-11-06 23:56:56 +09:00
f3b518fb62 Update yarn.lock (#5584) 2019-11-06 23:56:24 +09:00
1043 changed files with 32709 additions and 74948 deletions

View File

@ -1,76 +1,12 @@
version: 2.1
executors:
default:
working_directory: /tmp/workspace
docker:
- image: misskey/ci:v11-node11
- image: circleci/redis:latest
- image: circleci/postgres:latest
docker:
working_directory: /tmp/workspace
docker:
- image: docker:latest
jobs:
build:
executor: default
steps:
- checkout
- run:
name: Ensure yarn.lock
command: |
touch yarn.lock
- restore_cache:
name: Restore npm package caches
keys:
- yarn-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "yarn.lock" }}
- yarn-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-
- yarn-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-
- yarn-v1-arch-{{ arch }}-
- yarn-v1-
- run:
name: Install Dependencies
command: |
yarn install
- run:
name: Configure
command: |
cp .circleci/misskey/default.yml .config
cp .circleci/misskey/test.yml .config
- run:
name: Build
command: |
yarn build
touch yarn.lock
- save_cache:
name: Cache npm packages
key: yarn-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "yarn.lock" }}
paths:
- node_modules
- persist_to_workspace:
root: .
paths:
- .
test:
parameters:
executor:
type: string
default: "default"
executor: <<parameters.executor>>
steps:
- attach_workspace:
at: /tmp/workspace
- run:
name: Test
command: |
yarn test
touch yarn.lock
- save_cache:
name: Cache npm packages
key: yarn-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "yarn.lock" }}
paths:
- node_modules
docker:
parameters:
with_deploy:
@ -102,55 +38,8 @@ jobs:
workflows:
version: 2
nodejs:
jobs:
- hold:
name: manual-build-trigger
type: approval
filters:
branches:
ignore: master
- build:
name: manual-build
requires:
- manual-build-trigger
filters:
branches:
ignore: master
- build:
name: auto-build
filters:
branches:
only: master
- test:
name: manual-test
requires:
- manual-build
filters:
branches:
ignore: master
- test:
name: auto-test
requires:
- auto-build
filters:
branches:
only: master
docker:
jobs:
- hold:
name: manual-build-trigger
type: approval
filters:
branches:
ignore: master
- docker:
name: manual-build
requires:
- manual-build-trigger
filters:
branches:
ignore: master
- docker:
name: auto-build
with_deploy: true

View File

@ -1,12 +1,12 @@
url: 'http://misskey.local'
port: 80
mongodb:
port: 8080
db:
host: localhost
port: 27017
db: misskey
user: syuilo
port: 5432
db: test-misskey
user: postgres
pass: ''
redis:
host: localhost
port: 6379
pass: ''
id: aid

View File

@ -1,13 +1,12 @@
url: 'http://misskey.local'
port: 80
mongodb:
port: 8080
db:
host: localhost
port: 27017
port: 5432
db: test-misskey
user: admin
user: postgres
pass: ''
# __REDIS__
redis:
host: localhost
port: 6379
pass: ''
id: aid

View File

@ -111,10 +111,6 @@ id: 'aid'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
# If enabled:
# The first account created is automatically marked as Admin.
autoAdmin: true
# Whether disable HSTS
#disableHsts: true
@ -125,6 +121,14 @@ autoAdmin: true
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 16
# Job attempts
# deliverJobMaxAttempts: 12
# inboxJobMaxAttempts: 8
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4
@ -140,3 +144,6 @@ autoAdmin: true
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
# Media Proxy
#mediaProxy: https://example.com/proxy

1
.github/CODEOWNERS vendored
View File

@ -6,7 +6,6 @@
/.github/ @syuilo @AyaMorisawa @acid-chicken
/.vscode/ @acid-chicken
/assets/ @syuilo # @tamaina
/cli/ @syuilo
/docs/ @syuilo
/docs/*.en.md @AyaMorisawa # @skid9000
# /docs/*.fr.md @BoFFire

18
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: Docker build
on:
push:
branches:
- master
- develop
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Pull previous build result (for cache)
run: docker pull misskey/misskey:latest
- name: Build docker container
run: docker build --cache-from misskey/misskey:latest -t misskey/misskey .

42
.github/workflows/nodejs.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: Node.js CI
on:
push:
branches:
- master
- develop
pull_request:
jobs:
build_and_test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [11.10.x, 12.x]
services:
postgres:
image: postgres:10-alpine
ports:
- 5432:5432
env:
POSTGRES_DB: test-misskey
redis:
image: redis:alpine
ports:
- 6379:6379
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: yarn install
- name: Copy Configure
run: cp .circleci/misskey/*.yml .config
- name: Build
run: yarn build
- name: Test
run: yarn test

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
# Node.js
/node_modules
report.*.json
# config
/.config/*

5
.imgbotconfig Normal file
View File

@ -0,0 +1,5 @@
{
"ignoredFiles": [
"test/resources/*"
]
}

View File

@ -1,6 +1,190 @@
ChangeLog
=========
12.1.0 (2020/02/06)
--------------------
### ✨Improvements
* サーバー切断時に自動でリロードできるように
### 🐛Fixes
* もっと読み込むを続けていくと表示が遅くなっていく問題を修正
* Renote メニューが自分の投稿のRenoteでない限り表示されない問題を修正
* MFM jump, spin, title が効かない問題を修正
* AP: Likeで正しいActivity IDを提示するように修正
* AP: Misskey以外からのトークの返信が受け取れないのを修正
12.0.0 indigo (2020/02/06)
--------------------
Misskey v12では、クライアントが設計し直され、全く新しいUIに生まれ変わりました。
レスポンシブになり、ひとつのコードで様々なデバイスに対応できるようにしました。
各部で使用されるアニメーションは、ブラウザネイティブのトランジションを使用することでよりスムーズになりました。
目に見える変更だけではなく、内部的にも軽量化などの改善があります。
また、指定した条件にマッチする投稿を抽出できるタイムラインの追加や、インタラクティブな通知など、新機能もいくつかあります。
まだ未実装の機能(ウィジェット、テーマエディタ、リバーシ、フグパンチボタンなど)がありますが、今後のアップデートで復活します。
内部的には、コンポーネントの重複が解消され、ローカリゼーションも整理されたので、今後メンテナンスしやすくなっています。
さらに技術的なことを言うと、スタイルの記述に従来のStylusに代わってSCSSを採用し、開発の際にブラウザで編集したスタイルを持ってきやすくなるなどの改善が行なわれています。また、FontAwesomeコンポーネントに文字列形式でアイコンを指定するのをやめ、使用する都度アイコンをインポートするようにしました。これによりTree ShakingやCode Splittingとの相性が良くなります。
v12ではいくつかインスタンスにとって破壊的な変更がありますので、アップデートする前に以下の変更をお読みになりデータ(お知らせ)のバックアップなどお願いします。
アップデートが上手くいかない場合は、クリーンビルド(builtディレクトリを消した後、再度build)をお試しください。
### ⚠Breaking Changes
* お知らせがリセットされます。
* 通知がリセットされます。
* アカウントの外部サービス連携情報がリセットされます。
* インスタンスの閉鎖情報がリセットされます。
* プロキシアカウント設定情報がリセットされます。
* モデレーターがインスタンス設定を閲覧したり変更したりできなくなります(それらができるのはAdminのみになります)。
* モデレーターが出来るのは、ユーザーのサイレンス/凍結などに限られます。
* 従来と同じ権限を与えたい場合、モデレーターをAdminに設定することを検討してください(Adminは複数人設定可能です)。
* notes/search APIのページングがoffsetではなくuntilId方式に
* クライアントのテーマのフォーマットが調整されました。
* 旧テーマを変換してインポートする機能が予定されています
* ノートに位置情報を添付できる機能を廃止
* ノートに何のアプリから投稿したかという情報を含めるのを廃止
* Meta APIでサーバー内部の情報(マシン名、CPU情報など)を含めるのを廃止
### ✨Improvements
* Webクライアントを一新
* Syuilo Design System (仮称)を採用し、各コンポーネントが統一され一貫したデザインに
* レスポンシブデザインになり、デスクトップ/タブレット/スマートフォンで同じ機能が使えるように
* 複数アカウントに対応し、簡単に別のアカウントに切り替えられるように
* フォロー通知から直接フォローバックすることができるように
* 通知から直接フォローリクエストを許可/拒否できるように
* ユーザーの登録日を表示するように
* タイムラインウィジェットを追加
* 投稿フォームでメンションを追加するのが簡単に
* Renoteを解除できるように
* スマホ/タブレットでも絵文字ピッカーを使えるように
* ユーザーを選択する操作が便利に
* ユーザーページからユーザーにメッセージを送れるように
* ユーザーページからユーザーとトークを開始できるように
* ユーザーページからユーザー名をコピーできるように
* 非ログイン時のトップページにLTLではなくハイライトを表示するように
* 「戻る」ボタンを追加し、PWAフレンドリーに
* ストリーミングが切断された時にリロードできるようになり、PWAフレンドリーに
* タイムラインからユーザーページ等に遷移して戻ったときにタイムラインが初期化されないように
* 管理画面のカスタム絵文字一覧でページネーションを実装
* 二段階認証のトークンの有効期限を長く
* ESCキーでダイアログを閉じられるように
* 軽量化
* お知らせ機能の強化
* お知らせが未読か既読か管理されるようになり、未読のお知らせがあると分かりやすく表示されるように
* 何人がお知らせを読んだか分かるように
* アンテナ機能
* 指定した条件(キーワード、ファイル添付の有無など)にマッチする投稿のタイムラインを見れる機能
* 新しい投稿があったとき通知するようにもできる
* ウィジェットとしても表示可能
* Elasticsearchをインストールしなくても全文検索できるように
* リモートのカスタム絵文字をコピーしてくる機能を追加
* 自分の送ったフォローリクエストが承認されたときの通知を追加
* 絵文字判定正規表現と絵文字テーブルにUnicode 12.1分を追加
* TwemojiではサポートしているけどピッカーにないShibuya 109の絵文字を追加
* 韓国語のnyaizeを強化
* 外部サービス連携情報をプロフィールに表示しないように
* 今後個別に表示するかどうか設定できるようになる予定
* ハイライト投稿の並びを人気順ではなく投稿日時順に
* AIDのイズがあまりよくないのを改善
* WebAuthNで internal というタイプもあるようなのでそれも使えるように
* Allow CORS requests in /.well-known/* routes
* AP: リモート投稿にリモートでされたリアクションが表示されるように
* AP: Eventタイプのアクティビティをサポート
* AP: GroupとOrganizationを正規のActorとして受け付けるように
* AP: deliver/inbox 処理にインスタンス全体で流量制限をかけられるように
* AP: deliverのリトライ期間を長めにして、回数を変更できるように
* AP: Actorの鍵とkeyIdのフォーマットの変更
* 投稿する度にMastodonから3つずつリクエストが飛んできてしまう問題が解決し、双方の負荷が減って MastodonへのAP 配信所要時間が1/4~1/5に
* PixelFedへの配信ができるように
* AP: PixelFedのハッシュタグをハッシュタグ扱いできるように
* 他多数
### 🐛Fixes
* ミュートしている人からのリアクション通知があると、通知があると表示される問題を修正
* 投稿メニューを開いて操作した後にもう一度メニューを開こうとしてもできない問題を修正
* リモートのートのURLが書かれていた場合、動作がおかしい問題を修正
* リストTLだとTでのTLフォーカスが効かない問題を修正
* OAuth認証画面の配色がおかしい問題を修正
* 設定画面で、アバターを更新してもアバターの画像がその場で更新されない問題を修正
* 投稿詳細/ユーザー詳細 画面でadminや公式アカウントマークが表示されない問題を修正
* ハッシュタグ検索が遅い問題を修正
* APIのリクエスト方法(websocket/HTTP)によって返ってくるエラーの内容に違いがある問題を修正
* ストリーミングのuserListチャンネルで存在しないリストでもsubscribeできて、リストのIDがわかれば他人のリストでもsubscribeできる問題を修正
* Redis subscriberで認証ができないのを修正
* ファイルと画像認識処理の改善
* カスタム絵文字リアクションでないものは絵文字クエリをしないように
* トレンドで非公開な投稿のハッシュタグを集計しないように
* nyaizeの適用範囲の修正
* URLまでnyaizeされている問題を修正
* ハッシュタグまでnyaizeされている問題を修正
*
* 投稿フォームでCWが下書きに保存されない問題を修正
* 投稿フォームで公開範囲が下書きに保存されない問題を修正
* messaging/messages/read APIが正しく動作していなかった問題を修正
* TypeError: Cannot read property 'stack' of undefined が出ることがある問題を修正
* AP: カスタム絵文字を連続して書くと他のサービスでカスタム絵文字と認識されない問題を修正
* AP: audience (visibility) パースの修正
* AP: inboxの最小リトライ間隔 1秒→1分
* Pages: VERSION 変数が常に null な問題を修正
* Pages: DRPWPMが最初のしか出てこない問題を修正
* Pages: MY_NOTES_COUNT 変数が機能していなかったので削除
* Pages: MY_FOLLOWERS_COUNT 変数が機能していなかったので削除
* Pages: MY_FOLLOWING_COUNT 変数が機能していなかったので削除
11.37.1 (2020/01/07)
--------------------
### 🐛Fixes
* ファイルがアップロードできない問題を修正
11.37.0 (2020/01/07)
--------------------
### ✨Improvements
* AP引用でquoteUrlに対応
* トークの既読を連合
* 期限切れ/未保存リモートファイルのローカルプロキシ機能
* ミュート/ブロックでページングと解除ができるように
* Redis prefixにホスト名を使用するように
* AP Resolverの長いエラーメッセージをトリムするように
* 管理画面でstatsを継続リクエストしないように
* 凍結ユーザーのプロファイルなどを表示しないように
* クライアントで、thumbanilUrlが提供されていない画像はプレビューしないように
* svgでも画像の平均色を計算するように
* 画像の平均色を計算するとき、透過部分のある画像では一律で背景を#fff(白)に
* Pages: 小数点を丸める関数を追加
### 🐛Fixes
* カスタム絵文字リアクションの絵文字がNoteに添付されないのを修正
* リモートプロキシ時にサムネイルのContent-Typeがおかしい問題を修正
* /files/ 下のヘッダ設定タイミングを修正
* イベントが同じRedisを使用する他のMisskeyインスタンスに飛んでしまう問題を修正
* AP inbox Announce の処理の修正
* followers, direct投稿の存在がユーザーの投稿一覧に表示されている問題を修正
* Stacked bar chart がおかしいのを修正
* リストのインポートがエラーが出るとそこで終わってしまう問題を修正
* サムネイル/webpublicのファイル形式がjpeg/pngに固定されていたのをファイルを基に送出するように
* syslogが使えない問題を修正
11.36.0 (2019/11/24)
--------------------
### ✨Improvements
* ジョブキューで試行回数等を表示するように
* deliverエラー等の同じようなログが複数出てこないように、上でまとめて出すように
* deliverエラーのログではキューの詳細情報を格納しないように
* inbox/deliverのログに試行回数とキューが作られてからの時間を表示するように
* 無駄なAP deliverをしないように
* boot: remove setAttribute() calls and translate reload msg
### 🐛Fixes
* メンションの通知が届かない可能性がある問題を修正
* ブロックや閉鎖済みインスタンスのステータスが更新されてしまう問題を修正
* 「フォロワーを解除」アクティビティを正しく受け取らない問題を修正
* inboxのジョブキューが表示されない問題を修正
* ローカルにフォロワー限定投稿が流れてくる問題を修正
* リモートユーザーのアイコンがサムネイルで表示されない問題を修正
* DBとオブジェクトストレージのジョブキューが表示されない問題を修正
* エラーが発生したときにサーバーがクラッシュすることがある問題を修正
11.35.1 (2019/11/05)
--------------------
### 🐛Fixes

15
COPYING Normal file
View File

@ -0,0 +1,15 @@
Unless otherwise stated this repository is
Copyright © 2014-2020 syuilo and contributers
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
Misskey includes several third-party Open-Source softwares.
Unicode emoji regular expressions by Twitter, Inc.
License: MIT
https://github.com/twitter/twemoji-parser/blob/master/LICENSE.md
Emoji keywords for Unicode 11 and below by Mu-An Chiou
License: MIT
https://github.com/muan/emojilib/blob/master/LICENSE

View File

@ -1,6 +1,6 @@
<a href="https://xn--931a.moe/"><img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/></a>
[![Misskey](/assets/title.png)](https://misskey.io/)
[![Misskey](/assets/title.png)](https://join.misskey.page/)
================================================================
[![CircleCI](https://img.shields.io/circleci/project/github/syuilo/misskey.svg?style=for-the-badge&logo=circleci)](https://circleci.com/gh/syuilo/misskey)
@ -10,7 +10,7 @@
**A forever evolving, sophisticated microblogging platform.**
<p align="justify">
<a href="https://misskey.io">Misskey</a> is a decentralized microblogging platform born on Earth.
<a href="https://join.misskey.page/">Misskey</a> is a decentralized microblogging platform born on Earth.
Since it exists within the Fediverse (a universe where various social media platforms are organized),
it is mutually linked with other social media platforms.
Why don't you take a short break from the hustle and bustle of the city, and dive into a new Internet? <a href="https://join.misskey.page/">Find an instance!</a>
@ -103,84 +103,96 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
----------------------------------------------------------------
<!-- PATREON_START -->
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/20010324/b8af4bd31ae34fbf8806cc0e6228e400/1.png?token-time=2145916800&token-hash=iyiocfousNIUwASmatsIDq8EOsmLUdrQNkWyktHlmJg%3D" alt="Nemo" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/20832595" alt="Roujo" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/27956229" alt="Oliver Maximilian Seidel" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weepjp" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/605366/c9dc408fdcbf412fb183ca5b06235f8d/1.jpeg?token-time=2145916800&token-hash=oaqsjLqOFjWN5I9hm2epOaTXaEtKwQUy5OW-EpAz6-g%3D" alt="Jon Leibowitz" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19045173/cb91c0f345c24d4ebfd05f19906d5e26/1.png?token-time=2145916800&token-hash=o_zKBytJs_AxHwSYw_5R8eD0eSJe3RoTR3kR3Q0syN0%3D" alt="kiritan" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/24430516/b1964ac5b9f746d2a12ff53dbc9aa40a/1.jpg?token-time=2145916800&token-hash=bmEiMGYpp3bS7hCCbymjGGsHBZM3AXuBOFO3Kro37PU%3D" alt="Eduardo Quiros" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/14215107/1cbe1912c26143919fa0faca16f12ce1/3.png?token-time=2145916800&token-hash=Zq1TCK2tdY7xudEm_aV70bc_wxmol6pNj3ZWbpFUNbI%3D" alt="Nesakko" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/776209" alt="Denshi" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/557245" alt="mkatze" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=20010324">Nemo</a></td>
<td><a href="https://www.patreon.com/user?u=20832595">Roujo</a></td>
<td><a href="https://www.patreon.com/user?u=27956229">Oliver Maximilian Seidel</a></td>
<td><a href="https://www.patreon.com/weepjp">weepjp</a></td>
<td><a href="https://www.patreon.com/jonleibowitz">Jon Leibowitz</a></td>
<td><a href="https://www.patreon.com/user?u=19045173">kiritan</a></td>
<td><a href="https://www.patreon.com/user?u=24430516">Eduardo Quiros</a></td>
<td><a href="https://www.patreon.com/Nesakko">Nesakko</a></td>
<td><a href="https://www.patreon.com/user?u=776209">Denshi</a></td>
<td><a href="https://www.patreon.com/user?u=557245">mkatze</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/3075183/c2ae575c604e420297f000ccc396e395/1.jpeg?token-time=2145916800&token-hash=O9qmPtpo6wWb0OuvnkEekhk_1WO2MTdytLr7ZgsAr80%3D" alt="Liaizon Wakest" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/557245" alt="mkatze" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/23915207/25428766ecd745478e600b3d7f871eb2/1.png?token-time=2145916800&token-hash=urCLLA4KjJZX92Y1CxcBP4d8bVTHGkiaPnQZp-Tqz68%3D" alt="kabo2468y" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/8249688/4aacf36b6b244ab1bc6653591b6640df/2.png?token-time=2145916800&token-hash=1ZEf2w6L34253cZXS_HlVevLEENWS9QqrnxGUAYblPo%3D" alt="AureoleArk" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5670915/ee175f0bfb6347ffa4ea101a8c097bff/1.jpg?token-time=2145916800&token-hash=mPLM9CA-riFHx-myr3bLZJuH2xBRHA9se5VbHhLIOuA%3D" alt="osapon" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18899730/6a22797f68254034a854d69ea2445fc8/1.png?token-time=2145916800&token-hash=b_uj57yxo5VzkSOUS7oXE_762dyOTB_oxzbO6lFNG3k%3D" alt="YuzuRyo61" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5788159/af42076ab3354bb49803cfba65f94bee/1.jpg?token-time=2145916800&token-hash=iSaxp_Yr2-ZiU2YVi9rcpZZj9mj3UvNSMrZr4CU4qtA%3D" alt="mewl hayabusa" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1.png?token-time=2145916800&token-hash=9nEQje_eMvUjq9a7L3uBqW-MQbS-rRMaMgd7UYVoFNM%3D" alt="mydarkstar" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/16542964" alt="Takumi Sugita" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/28779508/3cd4cb7f017f4ee0864341e3464d42f9/1.png?token-time=2145916800&token-hash=eGQtR15be44kgvh8fw2Jx8Db4Bv15YBp2ldxh0EKRxA%3D" alt="S Y" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/wakest">Liaizon Wakest</a></td>
<td><a href="https://www.patreon.com/user?u=557245">mkatze</a></td>
<td><a href="https://www.patreon.com/user?u=23915207">kabo2468y</a></td>
<td><a href="https://www.patreon.com/AureoleArk">AureoleArk</a></td>
<td><a href="https://www.patreon.com/osapon">osapon</a></td>
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61</a></td>
<td><a href="https://www.patreon.com/hs_sh_net">mewl hayabusa</a></td>
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
<td><a href="https://www.patreon.com/user?u=16542964">Takumi Sugita</a></td>
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin</a></td>
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
<td><a href="https://www.patreon.com/user?u=28779508">S Y</a></td>
</tr></table>
<table><tr>
<td><img src="https://c8.patreon.com/2/200/16542964" alt="Takumi Sugita" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/26340354/08834cf767b3449e93098ef73a434e2f/2.png?token-time=2145916800&token-hash=nyM8DnKRL8hR47HQ619mUzsqVRpkWZjgtgBU9RY15Uc%3D" alt="totokoro" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5827393/59893c191dda408f9cabd0f20a3a5627/1.jpeg?token-time=2145916800&token-hash=i9N05vOph-eP1LTLb9_npATjYOpntL0ZsHNaZFSsPmE%3D" alt="motcha" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpe?token-time=2145916800&token-hash=CPxGQhKIlEaa6WUcgbyHixyKEhakiw9RFdOhsIJBQ_o%3D" alt="takimura" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/619ab87cc08448439222631ebb26802f/1.gif?token-time=2145916800&token-hash=o27K7M02s1z-LkDUEO5Oa7cu-GviRXeOXxryi4o_6VU%3D" alt="Atsuko Tominaga" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3.png?token-time=2145916800&token-hash=FTm3WVom4dJ9NwWMU4OpCL_8Yc13WiwEbKrDPyTZTPs%3D" alt="natalie" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5923936/2a743cbfbff946c2af3f09026047c0da/2.png?token-time=2145916800&token-hash=h6yphW1qnM0n_NOWaf8qtszMRLXEwIxfk5beu4RxdT0%3D" alt="noellabo" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1.jpe?token-time=2145916800&token-hash=qA8j97lIZNc-74AuZ0p4F3ms6sKPeKjtNt2vEuwpsyo%3D" alt="Hekovic" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpg?token-time=2145916800&token-hash=nVAntpybQrznE0rg05keLrSE6ogPKJXB13rmrJng42c%3D" alt="takimura" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13100201/fc5be4fa90444f09a9c8a06f72385272/1.png?token-time=2145916800&token-hash=i8PjlgfOB2LPEdbtWyx8ZPsBKhGcNZqcw_FQmH71UGU%3D" alt="aqz tamaina" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=16542964">Takumi Sugita</a></td>
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin</a></td>
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
<td><a href="https://www.patreon.com/user?u=26340354">totokoro</a></td>
<td><a href="https://www.patreon.com/user?u=19356899">sheeta.s</a></td>
<td><a href="https://www.patreon.com/user?u=5827393">motcha</a></td>
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
<td><a href="https://www.patreon.com/aqz">aqz tamaina</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/619ab87cc08448439222631ebb26802f/1.gif?token-time=2145916800&token-hash=o27K7M02s1z-LkDUEO5Oa7cu-GviRXeOXxryi4o_6VU%3D" alt="Atsuko Tominaga" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3.png?token-time=2145916800&token-hash=FTm3WVom4dJ9NwWMU4OpCL_8Yc13WiwEbKrDPyTZTPs%3D" alt="natalie" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5923936/2a743cbfbff946c2af3f09026047c0da/2.png?token-time=2145916800&token-hash=h6yphW1qnM0n_NOWaf8qtszMRLXEwIxfk5beu4RxdT0%3D" alt="noellabo" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1.jpg?token-time=2145916800&token-hash=7bkMqTwHPRsJPGAq42PYdDXDZBVGLqdgr1ZmBxX8GFQ%3D" alt="Hekovic" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/24641572/b4fd175424814f15b0ca9178d2d2d2e4/1.png?token-time=2145916800&token-hash=e2fyqdbuJbpCckHcwux7rbuW6OPkKdERcus0u2wIEWU%3D" alt="uroco @99" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1.jpeg?token-time=2145916800&token-hash=L55UhJ0rcuNAH3w_ryeeGN4hC6taoOixyAhraEi0bzw%3D" alt="dansup" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td>
<td><a href="https://www.patreon.com/user?u=4389829">natalie</a></td>
<td><a href="https://www.patreon.com/noellabo">noellabo</a></td>
<td><a href="https://www.patreon.com/Corset">CG</a></td>
<td><a href="https://www.patreon.com/hekovic">Hekovic</a></td>
<td><a href="https://www.patreon.com/user?u=24641572">uroco @99</a></td>
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1.jpeg?token-time=2145916800&token-hash=L55UhJ0rcuNAH3w_ryeeGN4hC6taoOixyAhraEi0bzw%3D" alt="dansup" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1.png?token-time=2145916800&token-hash=hBayGfOmQH3kRMdNnDe4oCZD_9fsJWSt29xXR3KRMVk%3D" alt="Nokotaro Takeda" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/23932002" alt="nenohi" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1.jpeg?token-time=2145916800&token-hash=vGe7wXGqmA8Q7m-kDNb6fyGdwk-Dxk4F-ut8ZZu51RM%3D" alt="Takashi Shibuya" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
<td><a href="https://www.patreon.com/user?u=23932002">nenohi</a></td>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table>
**Last updated:** Sat, 02 Nov 2019 18:09:05 UTC
**Last updated:** Wed, 05 Feb 2020 00:42:12 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright
----------------------------------------------------------------
> Copyright (c) 2014-2019 syuilo
Misskey is open-source software licensed under the [GNU AGPLv3](LICENSE).
[![][agpl-3.0-badge]][AGPL-3.0]
[agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html
[agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=for-the-badge
[backer-url]: #backers
[backer-badge]: https://opencollective.com/misskey/backers/badge.svg
[backers-image]: https://opencollective.com/misskey/backers.svg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

BIN
assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg8"
version="1.1"
viewBox="0 0 135.46667 135.46667"
height="512"
width="512">
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
style="fill:#2fa3bc;fill-opacity:1"
transform="translate(-30.809093,-111.78601)"
id="layer1">
<g
style="fill:#2fa3bc;fill-opacity:1"
transform="matrix(1.096096,0,0,1.096096,-2.960633,-44.023579)"
id="g4502">
<g
id="g5125"
transform="translate(-1.3333333e-6,-1.3439941e-6)"
style="fill:#2fa3bc;fill-opacity:1">
<g
aria-label="Mi"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.03404236px;line-height:476.69509888px;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';letter-spacing:0px;word-spacing:0px;fill:#2fa3bc;fill-opacity:1;stroke:none;stroke-width:0.28950602px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text4489"
transform="matrix(0.91391326,0,0,0.91391326,7.9719907,17.595761)">
<path
id="path5210"
transform="matrix(0.26412464,0,0,0.26412464,24.988264,136.28626)"
d="m 62.474609,76.585938 c -7.47555,0 -14.595784,1.246427 -21.359375,3.738281 C 29.011968,84.595952 19.044417,92.249798 11.212891,103.28516 3.7373405,113.96451 0,125.88934 0,139.06055 v 233.8789 c 0,17.08697 6.0510264,31.85913 18.154297,44.31836 12.459246,12.10327 27.233346,18.15625 44.320312,18.15625 17.442947,0 32.215089,-6.05298 44.318361,-18.15625 12.45925,-12.45923 18.68945,-27.23139 18.68945,-44.31836 V 330.4082 c 0.13441,-9.21122 9.6225,-6.79429 14.41797,0 8.98111,15.55395 28.02226,28.91242 50.19141,28.83594 22.16915,-0.0764 40.58194,-11.03699 50.19336,-28.83594 3.63981,-4.29263 13.89902,-11.60675 14.95117,0 v 42.53125 c 0,17.08697 6.05102,31.85913 18.15429,44.31836 12.45923,12.10327 27.23335,18.15625 44.32032,18.15625 17.44294,0 32.21509,-6.05298 44.31836,-18.15625 12.45923,-12.45923 18.68945,-27.23139 18.68945,-44.31836 v -233.8789 c 0,-13.17121 -3.9146,-25.09604 -11.74609,-35.77539 -7.47557,-11.035362 -17.26588,-18.689208 -29.36914,-22.960941 -7.11956,-2.491854 -14.23982,-3.738281 -21.35938,-3.738281 -19.22286,0 -35.41865,7.476649 -48.58984,22.427734 l -63.40235,74.199218 c -1.42391,1.06791 -6.14093,9.23242 -16.16015,9.23242 -10.01923,0 -14.20109,-8.16451 -15.625,-9.23242 L 110.53125,99.013672 C 97.716024,84.062587 81.697447,76.585938 62.474609,76.585938 Z m 395.060551,0 c -14.9511,-10e-7 -27.76596,5.340179 -38.44532,16.019531 -10.32338,10.323381 -15.48437,22.961011 -15.48437,37.912111 0,14.9511 5.16099,27.76596 15.48437,38.44531 10.67936,10.32338 23.49422,15.48633 38.44532,15.48633 14.95109,0 27.76596,-5.16295 38.44531,-15.48633 C 506.65982,158.28354 512,145.46868 512,130.51758 512,115.56648 506.65982,102.92885 495.98047,92.605469 485.30112,81.926117 472.48625,76.585938 457.53516,76.585938 Z m 0.5332,118.541012 c -14.9511,0 -27.76596,5.34018 -38.44531,16.01953 -10.67936,10.67936 -16.01758,23.49422 -16.01758,38.44532 v 131.89062 c 0,14.9511 5.33822,27.76596 16.01758,38.44531 10.67935,10.32339 23.49421,15.48633 38.44531,15.48633 14.9511,0 27.58873,-5.16294 37.91211,-15.48633 C 506.65982,409.24838 512,396.43352 512,381.48242 V 249.5918 c 0,-14.9511 -5.34018,-27.76596 -16.01953,-38.44532 -10.32338,-10.67935 -22.96101,-16.01953 -37.91211,-16.01953 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill:#2fa3bc;fill-opacity:1;stroke-width:1.09609616px" />
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

BIN
assets/icon.afdesign Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

View File

@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg8"
version="1.1"
viewBox="0 0 135.46667 135.46667"
height="512"
width="512"
sodipodi:docname="icon.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
inkscape:export-filename="H:\misskey\assets\icons\512.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="965"
id="namedview10"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-page="true"
inkscape:zoom="0.921875"
inkscape:cx="219.9952"
inkscape:cy="361.00053"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<rect
style="opacity:1;fill:#2ba3bc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.32291675;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect828"
width="135.46667"
height="135.46667"
x="1.896631e-16"
y="0" />
<g
transform="matrix(0.57430748,0,0,0.57430748,11.070705,-35.453717)"
id="layer1"
style="stroke-width:1.74122751;fill:#ffffff;fill-opacity:1">
<g
transform="matrix(1.096096,0,0,1.096096,-2.960633,-44.023579)"
id="g4502"
style="stroke-width:1.74122751;fill:#ffffff;fill-opacity:1">
<g
id="g5125"
transform="translate(-1.3333333e-6,-1.3439941e-6)"
style="fill:#ffffff;fill-opacity:1;stroke-width:1.74122751">
<g
aria-label="Mi"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.03404236px;line-height:476.69509888px;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.50409585px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text4489"
transform="matrix(0.91391326,0,0,0.91391326,7.9719907,17.595761)">
<path
id="path5210"
transform="matrix(0.26412464,0,0,0.26412464,24.988264,136.28626)"
d="m 62.474609,76.585938 c -7.47555,0 -14.595784,1.246427 -21.359375,3.738281 C 29.011968,84.595952 19.044417,92.249798 11.212891,103.28516 3.7373405,113.96451 0,125.88934 0,139.06055 v 233.8789 c 0,17.08697 6.0510264,31.85913 18.154297,44.31836 12.459246,12.10327 27.233346,18.15625 44.320312,18.15625 17.442947,0 32.215089,-6.05298 44.318361,-18.15625 12.45925,-12.45923 18.68945,-27.23139 18.68945,-44.31836 V 330.4082 c 0.13441,-9.21122 9.6225,-6.79429 14.41797,0 8.98111,15.55395 28.02226,28.91242 50.19141,28.83594 22.16915,-0.0764 40.58194,-11.03699 50.19336,-28.83594 3.63981,-4.29263 13.89902,-11.60675 14.95117,0 v 42.53125 c 0,17.08697 6.05102,31.85913 18.15429,44.31836 12.45923,12.10327 27.23335,18.15625 44.32032,18.15625 17.44294,0 32.21509,-6.05298 44.31836,-18.15625 12.45923,-12.45923 18.68945,-27.23139 18.68945,-44.31836 v -233.8789 c 0,-13.17121 -3.9146,-25.09604 -11.74609,-35.77539 -7.47557,-11.035362 -17.26588,-18.689208 -29.36914,-22.960941 -7.11956,-2.491854 -14.23982,-3.738281 -21.35938,-3.738281 -19.22286,0 -35.41865,7.476649 -48.58984,22.427734 l -63.40235,74.199218 c -1.42391,1.06791 -6.14093,9.23242 -16.16015,9.23242 -10.01923,0 -14.20109,-8.16451 -15.625,-9.23242 L 110.53125,99.013672 C 97.716024,84.062587 81.697447,76.585938 62.474609,76.585938 Z m 395.060551,0 c -14.9511,-10e-7 -27.76596,5.340179 -38.44532,16.019531 -10.32338,10.323381 -15.48437,22.961011 -15.48437,37.912111 0,14.9511 5.16099,27.76596 15.48437,38.44531 10.67936,10.32338 23.49422,15.48633 38.44532,15.48633 14.95109,0 27.76596,-5.16295 38.44531,-15.48633 C 506.65982,158.28354 512,145.46868 512,130.51758 512,115.56648 506.65982,102.92885 495.98047,92.605469 485.30112,81.926117 472.48625,76.585938 457.53516,76.585938 Z m 0.5332,118.541012 c -14.9511,0 -27.76596,5.34018 -38.44531,16.01953 -10.67936,10.67936 -16.01758,23.49422 -16.01758,38.44532 v 131.89062 c 0,14.9511 5.33822,27.76596 16.01758,38.44531 10.67935,10.32339 23.49421,15.48633 38.44531,15.48633 14.9511,0 27.58873,-5.16294 37.91211,-15.48633 C 506.65982,409.24838 512,396.43352 512,381.48242 V 249.5918 c 0,-14.9511 -5.34018,-27.76596 -16.01953,-38.44532 -10.32338,-10.67935 -22.96101,-16.01953 -37.91211,-16.01953 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill:#ffffff;fill-opacity:1;stroke-width:1.90855289px"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg8"
version="1.1"
viewBox="0 0 135.46667 135.46667"
height="512"
width="512">
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-30.809093,-111.78601)"
id="layer1">
<g
transform="matrix(1.096096,0,0,1.096096,-2.960633,-44.023579)"
id="g4502">
<g
id="g5125"
transform="translate(-1.3333333e-6,-1.3439941e-6)"
style="fill:#000000;fill-opacity:1">
<g
aria-label="Mi"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.03404236px;line-height:476.69509888px;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28950602px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text4489"
transform="matrix(0.91391326,0,0,0.91391326,7.9719907,17.595761)">
<path
id="path5210"
transform="matrix(0.26412464,0,0,0.26412464,24.988264,136.28626)"
d="m 62.474609,76.585938 c -7.47555,0 -14.595784,1.246427 -21.359375,3.738281 C 29.011968,84.595952 19.044417,92.249798 11.212891,103.28516 3.7373405,113.96451 0,125.88934 0,139.06055 v 233.8789 c 0,17.08697 6.0510264,31.85913 18.154297,44.31836 12.459246,12.10327 27.233346,18.15625 44.320312,18.15625 17.442947,0 32.215089,-6.05298 44.318361,-18.15625 12.45925,-12.45923 18.68945,-27.23139 18.68945,-44.31836 V 330.4082 c 0.13441,-9.21122 9.6225,-6.79429 14.41797,0 8.98111,15.55395 28.02226,28.91242 50.19141,28.83594 22.16915,-0.0764 40.58194,-11.03699 50.19336,-28.83594 3.63981,-4.29263 13.89902,-11.60675 14.95117,0 v 42.53125 c 0,17.08697 6.05102,31.85913 18.15429,44.31836 12.45923,12.10327 27.23335,18.15625 44.32032,18.15625 17.44294,0 32.21509,-6.05298 44.31836,-18.15625 12.45923,-12.45923 18.68945,-27.23139 18.68945,-44.31836 v -233.8789 c 0,-13.17121 -3.9146,-25.09604 -11.74609,-35.77539 -7.47557,-11.035362 -17.26588,-18.689208 -29.36914,-22.960941 -7.11956,-2.491854 -14.23982,-3.738281 -21.35938,-3.738281 -19.22286,0 -35.41865,7.476649 -48.58984,22.427734 l -63.40235,74.199218 c -1.42391,1.06791 -6.14093,9.23242 -16.16015,9.23242 -10.01923,0 -14.20109,-8.16451 -15.625,-9.23242 L 110.53125,99.013672 C 97.716024,84.062587 81.697447,76.585938 62.474609,76.585938 Z m 395.060551,0 c -14.9511,-10e-7 -27.76596,5.340179 -38.44532,16.019531 -10.32338,10.323381 -15.48437,22.961011 -15.48437,37.912111 0,14.9511 5.16099,27.76596 15.48437,38.44531 10.67936,10.32338 23.49422,15.48633 38.44532,15.48633 14.95109,0 27.76596,-5.16295 38.44531,-15.48633 C 506.65982,158.28354 512,145.46868 512,130.51758 512,115.56648 506.65982,102.92885 495.98047,92.605469 485.30112,81.926117 472.48625,76.585938 457.53516,76.585938 Z m 0.5332,118.541012 c -14.9511,0 -27.76596,5.34018 -38.44531,16.01953 -10.67936,10.67936 -16.01758,23.49422 -16.01758,38.44532 v 131.89062 c 0,14.9511 5.33822,27.76596 16.01758,38.44531 10.67935,10.32339 23.49421,15.48633 38.44531,15.48633 14.9511,0 27.58873,-5.16294 37.91211,-15.48633 C 506.65982,409.24838 512,396.43352 512,381.48242 V 249.5918 c 0,-14.9511 -5.34018,-27.76596 -16.01953,-38.44532 -10.32338,-10.67935 -22.96101,-16.01953 -37.91211,-16.01953 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill:#000000;fill-opacity:1;stroke-width:1.09609616px" />
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -88,7 +88,7 @@ Just `docker-compose up -d`. GLHF!
7. `docker-compose stop && docker-compose up -d`
### How to execute [cli commands](manage.en.md):
`docker-compose run --rm web node cli/mark-admin @example`
`docker-compose run --rm web node built/tools/mark-admin @example`
----------------------------------------------------------------

View File

@ -55,7 +55,7 @@ Utilisez la commande `docker-compose up -d`. GLHF!
7. `docker-compose stop && docker-compose up -d`
### Comment exécuter des [commandes](manage.fr.md)
`docker-compose run --rm web node cli/mark-admin @example`
`docker-compose run --rm web node built/tools/mark-admin @example`
### Configuration d'ElasticSearch (pour la fonction de recherche)
*1.* Préparation de l'environnement

View File

@ -89,7 +89,7 @@ docker-compose run --rm web yarn run init
### cliコマンドを実行する方法:
`docker-compose run --rm web node cli/mark-admin @example`
`docker-compose run --rm web node built/tools/mark-admin @example`
----------------------------------------------------------------

View File

@ -5,14 +5,10 @@ coming soon
## Mark as 'admin' user
``` shell
node cli/mark-admin (User-ID or Username)
node built/tools/mark-admin (Username)
```
e.g.
``` shell
# By id
node cli/mark-admin 57d01a501fdf2d07be417afe
# By username
node cli/suspend @syuilo
node built/tools/mark-admin @syuilo
```

View File

@ -5,14 +5,10 @@ coming soon
## Marquer un utilisateur en tant que 'admin'
``` shell
node cli/mark-admin (ID utilisateur ou nom d'utilisateur)
node built/tools/mark-admin (nom d'utilisateur)
```
Exemple :
``` shell
# Par id
node cli/mark-admin 57d01a501fdf2d07be417afe
# Par nom d'utilisateur
node cli/suspend @syuilo
node built/tools/mark-admin @syuilo
```

View File

@ -5,14 +5,10 @@ coming soon
## 管理者ユーザーを設定する
``` shell
node cli/mark-admin (ユーザーID または ユーザー名)
node built/tools/mark-admin (ユーザー名)
```
例:
``` shell
# ユーザーID
node cli/mark-admin 57d01a501fdf2d07be417afe
# ユーザー名
node cli/mark-admin @syuilo
node built/tools/mark-admin @syuilo
```

View File

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
Please install and setup these softwares:
#### Dependencies :package:
* **[Node.js](https://nodejs.org/en/)** >= 11.7.0
* **[Node.js](https://nodejs.org/en/)** >= 11.10.1
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
* **[Redis](https://redis.io/)**

View File

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
Installez les paquets suivants :
#### Dépendences :package:
* **[Node.js](https://nodejs.org/en/)** >= 11.7.0
* **[Node.js](https://nodejs.org/en/)** >= 11.10.1
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
* **[Redis](https://redis.io/)**

View File

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
これらのソフトウェアをインストール・設定してください:
#### 依存関係 :package:
* **[Node.js](https://nodejs.org/en/)** (11.7.0以上)
* **[Node.js](https://nodejs.org/en/)** (11.10.1以上)
* **[PostgreSQL](https://www.postgresql.org/)** (10以上)
* **[Redis](https://redis.io/)**

View File

@ -2,43 +2,26 @@
* Gulp tasks
*/
import * as fs from 'fs';
import * as gulp from 'gulp';
import * as gutil from 'gulp-util';
import * as ts from 'gulp-typescript';
const sourcemaps = require('gulp-sourcemaps');
import tslint from 'gulp-tslint';
const cssnano = require('gulp-cssnano');
const stylus = require('gulp-stylus');
import * as uglifyComposer from 'gulp-uglify/composer';
import * as rimraf from 'rimraf';
import chalk from 'chalk';
import * as rename from 'gulp-rename';
import * as mocha from 'gulp-mocha';
import * as replace from 'gulp-replace';
const uglifyes = require('uglify-es');
import * as rimraf from 'rimraf';
import * as rename from 'gulp-rename';
const cleanCSS = require('gulp-clean-css');
const sass = require('gulp-dart-sass');
const fiber = require('fibers');
const locales = require('./locales');
const uglify = uglifyComposer(uglifyes, console);
const env = process.env.NODE_ENV || 'development';
const isProduction = env === 'production';
const isDebug = !isProduction;
if (isDebug) {
console.warn(chalk.yellow.bold('WARNING! NODE_ENV is not "production".'));
console.warn(chalk.yellow.bold(' built script will not be compressed.'));
}
const meta = require('./package.json');
gulp.task('build:ts', () => {
const tsProject = ts.createProject('./tsconfig.json');
return tsProject
.src()
.pipe(sourcemaps.init())
.pipe(tsProject())
.on('error', () => {})
.pipe(sourcemaps.write('.', { includeContent: false, sourceRoot: '../built' }))
.pipe(gulp.dest('./built/'));
});
@ -46,37 +29,62 @@ gulp.task('build:copy:views', () =>
gulp.src('./src/server/web/views/**/*').pipe(gulp.dest('./built/server/web/views'))
);
gulp.task('build:copy:fonts', () =>
gulp.src('./node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/client/assets/fonts/'))
);
gulp.task('build:copy:locales', cb => {
fs.mkdirSync('./built/client/assets/locales', { recursive: true });
gulp.task('build:copy', gulp.parallel('build:copy:views', 'build:copy:fonts', () =>
for (const [lang, locale] of Object.entries(locales)) {
fs.writeFileSync(`./built/client/assets/locales/${lang}.${meta.version}.json`, JSON.stringify(locale), 'utf-8');
}
cb();
});
gulp.task('build:copy', gulp.parallel('build:copy:views', 'build:copy:locales', () =>
gulp.src([
'./src/const.json',
'./src/emojilist.json',
'./src/server/web/views/**/*',
'./src/**/assets/**/*',
'!./src/client/app/**/assets/**/*'
'!./src/client/assets/**/*'
]).pipe(gulp.dest('./built/'))
));
gulp.task('lint', () =>
gulp.src('./src/**/*.ts')
.pipe(tslint({
formatter: 'verbose'
}))
.pipe(tslint.report())
gulp.task('clean', cb =>
rimraf('./built', cb)
);
gulp.task('format', () =>
gulp.src('./src/**/*.ts')
.pipe(tslint({
formatter: 'verbose',
fix: true
}))
.pipe(tslint.report())
gulp.task('cleanall', gulp.parallel('clean', cb =>
rimraf('./node_modules', cb)
));
gulp.task('build:client:styles', () =>
gulp.src('./src/client/style.scss')
.pipe(sass({ fiber }))
.pipe(cleanCSS())
.pipe(gulp.dest('./built/client/assets/'))
);
gulp.task('copy:client', () =>
gulp.src([
'./assets/**/*',
'./src/client/assets/**/*',
])
.pipe(rename(path => {
path.dirname = path.dirname!.replace('assets', '.');
}))
.pipe(gulp.dest('./built/client/assets/'))
);
gulp.task('build:client', gulp.parallel(
'build:client:styles',
'copy:client'
));
gulp.task('build', gulp.parallel(
'build:ts',
'build:copy',
'build:client',
));
gulp.task('mocha', () =>
gulp.src('./test/**/*.ts')
.pipe(mocha({
@ -87,64 +95,4 @@ gulp.task('mocha', () =>
gulp.task('test', gulp.task('mocha'));
gulp.task('clean', cb =>
rimraf('./built', cb)
);
gulp.task('cleanall', gulp.parallel('clean', cb =>
rimraf('./node_modules', cb)
));
gulp.task('build:client:script', () => {
const client = require('./built/meta.json');
return gulp.src(['./src/client/app/boot.js', './src/client/app/safe.js'])
.pipe(replace('VERSION', JSON.stringify(client.version)))
.pipe(replace('ENV', JSON.stringify(env)))
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
.pipe(isProduction ? uglify({
toplevel: true
} as any) : gutil.noop())
.pipe(gulp.dest('./built/client/assets/'));
});
gulp.task('build:client:styles', () =>
gulp.src('./src/client/app/init.css')
.pipe(isProduction
? (cssnano as any)()
: gutil.noop())
.pipe(gulp.dest('./built/client/assets/'))
);
gulp.task('copy:client', () =>
gulp.src([
'./assets/**/*',
'./src/client/assets/**/*',
'./src/client/app/*/assets/**/*'
])
.pipe(rename(path => {
path.dirname = path.dirname!.replace('assets', '.');
}))
.pipe(gulp.dest('./built/client/assets/'))
);
gulp.task('doc', () =>
gulp.src('./src/docs/**/*.styl')
.pipe(stylus())
.pipe((cssnano as any)())
.pipe(gulp.dest('./built/docs/assets/'))
);
gulp.task('build:client', gulp.parallel(
'build:client:script',
'build:client:styles',
'copy:client'
));
gulp.task('build', gulp.parallel(
'build:ts',
'build:copy',
'build:client',
'doc'
));
gulp.task('default', gulp.task('build'));

View File

@ -1 +0,0 @@
---

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,952 +1 @@
---
meta:
lang: "Deutsch"
common:
misskey: "Ein ⭐ des Fediversums"
about-title: "Ein ⭐ des Fediversums."
about: "Danke, dass Du Misskey gefunden hast. Misskey ist eine <b>dezentralisierte Microblogging-Plattform</b>, welche auf der ganzen Welt verteilt ist. Da es innerhalb es Fediversums existiert (ein Universum, in dem verschiedene Soziale Netzwerke organisiert sind), ist es unmittelbar mit anderen sozialen Netzwerken verbunden. Warum nimmst du dir nicht einmal eine Auszeit von dem Trubel der Stadt und tauchst in das neue Internet hinein?"
intro:
title: "Was ist Misskey?"
about: "Misskey ist eine Quelloffene, <b>dezentralisierte microblogging Software</b>. Es bietet eine erweiterbare Benutzeroberfläche, verschiedenste Möglichkeiten auf Beiträge zu reagieren, kostenlosen Datenspeicher, und andere fortschrittliche Funktionen. Zusätzlich ist Misskey dazu in der Lage, sich mittels des Fediverse mit beliebig vielen anderen ActivityPub-kompatiblen Diensten zu verbinden. Wenn du zum Beispiel einen Betrag mit Misskey abschickst, wird dieser auch für Nutzer von Mastodon oder Pleroma sichtbar sein. So ähnlich wie eine Radioübertragung zwischen Planeten."
features: "Funktionen"
rich-contents: "Notizen"
rich-contents-desc: "Poste einfach deine Ideen, Interessen und alles, was du teilen möchtest. Gestalte deine Nachrichten, teile deine Lieblingsbilder, sende Dateien und Videos und erstelle Umfragen das und mehr kann Misskey!"
reaction: "Reaktionen"
reaction-desc: "Der einfachste Weg, deine Gefühle mit anderen zu teilen. Mit Misskey kannst du auf verschiedenste Arten auf Beiträge reagieren, statt nur zu „liken“."
ui: "Benutzeroberfläche"
ui-desc: "Geschmäcker sind verschieden. Deswegen ist Misskeys Oberfläche hochanpassbar und modular. Mache die Startseite zu deiner Startseite, indem du das Layout deiner Timeline änderst und mit Widgets staffierst."
drive: "Drive"
drive-desc: "Du willst ein hochgeladenes Foto nochmal posten? Deine Dateien benennen und in Ordnern sortieren? Misskeys Drive ist der beste Ort dafür. Damit wird das Teilen zum Kinderspiel!"
outro: "Probiere Misskey aus und entdecke Misskeys einzigartige Funktionen. Wenn dir diese Instanz nicht zusagt, nimm einfach eine andere. Dank Misskeys dezentralem System kannst du dich überall mit deinen Freunden verbinden. Also dann, GLHF!"
application-authorization: "Autorisierte Anwendungen"
close: "Schließen"
do-not-copy-paste: "Bitte keinen Code einfügen. Ihr Account könnte gefährdet werden."
load-more: "Mehr laden"
enter-password: "Bitte Passwort eingeben"
2fa: "Zwei-Faktor-Authentifizierung"
customize-home: "Layout Anpassen"
featured-notes: "Beliebt"
dark-mode: "Dunkler Modus"
signin: "Einloggen"
signup: "Registrieren"
signout: "Ausloggen"
reload-to-apply-the-setting: "Die Seite muss zum Übernehmen dieser Einstellung aktualisiert werden. Soll die Seite jetzt neu geladen werden?"
fetching-as-ap-object: "Hole Daten…"
delete-confirm: "Diesen Beitrag löschen?"
notification-types:
reply: "Antworten"
renote: "Anmerkung"
got-it: "Verstanden!"
customization-tips:
title: "Anpassung-Tipps"
paragraph: "<p>Du kannst deine Startseite anpassen, indem du Widgets hinzufügst und verschiebst.</p><p><strong>Klicke <strong>rechts</strong></strong> auf ein Widget, um dessen Aussehen zu verändern.</p><p>Um ein Widget zu löschen, klicke und ziehe es auf den <strong>Papierkorb</strong> am Kopfende der Seite.</p><p>Wenn du fertig bist, drücke auf den Beenden-Knopf oben rechts.</p>"
gotit: "Verstanden!"
notification:
file-uploaded: "Datei hochgeladen!"
message-from: "Nachricht von {}:"
reversi-invited: "Zu einem Spiel eingeladen"
reversi-invited-by: "Eingeladen von {}:"
notified-by: "Benachrichtigt von {}:"
reply-from: "Antwort von {}:"
quoted-by: "Zitiert von {}:"
time:
unknown: "Unbekannt"
future: "Zukunft"
just_now: "Gerade eben"
seconds_ago: "vor {} Sekunde(n)"
minutes_ago: "vor {} Minute(n)"
hours_ago: "vor {} Stunde(n)"
days_ago: "vor {} Tag(en)"
weeks_ago: "vor {} Woche(n)"
months_ago: "vor {} Monat(en)"
years_ago: "vor {} Jahr(en)"
month-and-day: "{day}/{month}"
trash: "Papierkorb"
drive: "Drive"
pages: "Seite"
messaging: "Unterhaltungen"
home: "Home"
deck: "Deck"
timeline: "Zeitleiste"
explore: "Entdecken"
following: "Folgt"
followers: "Folgende"
favorites: "Favoriten"
permissions:
"read:account": "Accountinformationen anzeigen."
"write:account": "Accountinformationen bearbeiten."
"read:blocks": "Blöcke anzeigen"
"write:blocks": "Auf Sperrungen zugreifen"
"read:drive": "Dateien anzeigen"
"write:drive": "Dateien bearbeiten"
"read:favorites": "Favoriten anzeigen"
"write:favorites": "Auf Favoriten zugreifen"
"read:following": "Follower-Daten lesen"
"write:following": "Folgestatus bearbeiten"
"read:messaging": "Unterhaltung anzeigen"
"write:messaging": "Unterhaltung bearbeiten"
"read:mutes": "Stummschaltungen lesen"
"write:mutes": "Stummschaltungen bearbeiten"
"write:notes": "Beiträge löschen und verfassen"
"read:notifications": "Benachrichtigungen lesen"
"write:notifications": "Benachrichtigungen bearbeiten"
"read:reactions": "Reaktionen sehen"
"write:reactions": "Reaktionen hinzufügen und bearbeiten"
"write:votes": "Abstimmen"
empty-timeline-info:
follow-users-to-make-your-timeline: "Beiträge von Benutzern, denen du folgst, werden in der Zeitleiste angezeigt."
explore: "Benutzer finden"
post-form:
reply: "Antworten"
renote: "Anmerkung"
enter-username: "Bitte gib einen Benutzernamen ein"
username-prompt: "Bitte gib einen Benutzernamen ein"
weekday-short:
sunday: "So"
monday: "Mo"
tuesday: "Di"
wednesday: "Mi"
thursday: "Do"
friday: "Fr"
saturday: "Sa"
weekday:
sunday: "Sonntag"
monday: "Montag"
tuesday: "Dienstag"
wednesday: "Mittwoch"
thursday: "Donnerstag"
friday: "Freitag"
saturday: "Samstag"
reactions:
like: "Gefällt mir"
love: "Lieben"
laugh: "Lachen"
hmm: "Hmm...?"
surprise: "Wow"
congrats: "Glückwunsch!"
angry: "Wütend"
confused: "Verwirrt"
rip: "RIP"
pudding: "Pudding"
note-visibility:
public: "Öffentlich"
home: "Startseite"
home-desc: "Auf die Startseite posten"
followers: "Abonnenten"
followers-desc: "Nur für diejenigen sichtbar, die dir folgen"
specified: "Direkt"
specified-desc: "Nur für bestimmte Benutzer sichtbar"
local-public: "Öffentlich (nur lokal)"
local-home: "Home (nur lokal)"
local-followers: "Follower (nur lokal)"
note-placeholders:
a: "Was machst du gerade?"
b: "Was ist so passiert?"
c: "Was geht dir durch den Kopf?"
d: "Willst du etwas sagen?"
e: "Schreib hier etwas!"
f: "Warte darauf, das du schreibst..."
settings: "Einstellungen"
_settings:
profile: "Dein Profil"
notification: "Benachrichtigungen"
apps: "Anwendungen"
tags: "Hashtags"
mute-and-block: "Stummschalten/Blocken"
blocking: "Blocken"
security: "Sicherheit"
signin: "Login-Verlauf"
password: "Passwort"
other: "Mehr"
appearance: "Designs"
behavior: "Verhalten"
fetch-on-scroll: "Unendliches laden beim scrollen"
fetch-on-scroll-desc: "Wenn beim scrollen das Ende erreicht wird, lädt die Anwendung automatisch neue Inhalte nach."
note-visibility: "Sichtbarkeit von Beiträgen"
default-note-visibility: "Die Standardsichtbarkeit"
remember-note-visibility: "Erinnerung an Sichtbarkeit von Beiträgen"
web-search-engine: "Web-Suchmaschine"
web-search-engine-desc: "Beispiel: https://www.google.de/search?q={{query}}"
keep-cw: "Inhaltswarnung beibehalten"
keep-cw-desc: "Wenn auf einen Beitrag geantwortet wird, wird die Inhaltswarnung des Originalbeitrags übernommen."
i-like-sushi: "Ich bevorzuge Sushi anstelle von Pudding"
show-reversi-board-labels: "Zeige Reihen- und Spaltenbeschreibungen in Reversi an"
use-avatar-reversi-stones: "Avatar als Stein in Reversi anzeigen"
disable-animated-mfm: "Animierten Text in Beiträgen deaktivieren"
disable-showing-animated-images: "Animierte Grafiken deaktivieren"
suggest-recent-hashtags: "Beim Verfassen von Beiträgen letzte Hashtags anzeigen"
always-show-nsfw: "Sensible Inhalte (NSFW) immer anzeigen"
always-mark-nsfw: "Meine Anhänge immer als NSFW markieren"
show-full-acct: "Servername bei Benutzernamen immer anzeigen"
show-via: "„via“ anzeigen"
reduce-motion: "Animationen der Benutzeroberfläche reduzieren"
this-setting-is-this-device-only: "Nur auf diesem Gerät"
use-os-default-emojis: "Betriebssystem-Emojis nutzen"
line-width: "Linienstärke"
line-width-thin: "Dünn"
line-width-normal: "Normal"
line-width-thick: "Dick"
font-size: "Schriftgröße"
font-size-x-small: "Sehr klein"
font-size-small: "Klein"
font-size-medium: "Normal"
font-size-large: "Groß"
font-size-x-large: "Sehr groß"
deck-column-align: "Spaltenaufteilung der Deck-Ansicht"
deck-column-align-center: "Mitte"
deck-column-align-left: "Links"
deck-column-align-flexible: "Flexibel"
deck-column-width: "Spaltenbreite des Decks"
deck-column-width-narrow: "Sehr eng"
deck-column-width-narrower: "Eng"
deck-column-width-normal: "Normal"
deck-column-width-wider: "Breit"
deck-column-width-wide: "Sehr breit"
use-shadow: "Nutze Schatten"
rounded-corners: "Abgerundete Ecken"
circle-icons: "Kreisförmige Avatar"
contrasted-acct: "Nutzernamen kontrastreicher darstellen"
wallpaper: "Hintergrund"
choose-wallpaper: "Hintergrund auswählen"
delete-wallpaper: "Hintergrund entfernen"
post-form-on-timeline: "Beitragsformular über Timeline anzeigen"
show-clock-on-header: "Uhr am oberen rechten Rand anzeigen"
show-reply-target: "Zeige bei einer Antwort die ursprüngliche Nachricht"
timeline: "Timeline"
show-my-renotes: "Zeige eigene Renotes in der Timeline"
show-renoted-my-notes: "Zeige Renotes deiner Posts in der Timeline"
show-local-renotes: "Zeige Renotes lokaler Posts in der Timeline"
remain-deleted-note: "Gelöschte Beiträge weiterhin anzeigen"
sound: "Töne"
enable-sounds: "Töne aktivieren"
enable-sounds-desc: "Spiel einen Ton ab beim Erhalten eines Beitrags bzw. einer Nachricht. Diese Einstellung wird im Browser gespeichert."
volume: "Lautstärke"
test: "Test"
update: "Misskey-Update"
version: "Version:"
latest-version: "Neuste Version:"
update-checking: "Suche nach Updates"
do-update: "Nach Updates suchen"
update-settings: "Erweiterte Einstellungen"
no-updates: "Kein Update verfügbar"
no-updates-desc: "Misskey ist aktuell."
update-available: "Eine neue Version ist verfügbar!"
update-available-desc: "Änderungen werden beim Neuladen der Seite angewendet."
advanced-settings: "Erweiterte Einstellungen"
debug-mode: "Debug-Modus einschalten"
debug-mode-desc: "Diese Einstellung wird im Browser gespeichert."
navbar-position: "Postion der Navigationsleiste"
navbar-position-top: "Oben"
navbar-position-left: "Links"
navbar-position-right: "Rechts"
i-am-under-limited-internet: "Ich möchte Datenvolumen sparen"
post-style: "Beitrags-Anzeigestil"
post-style-standard: "Standard"
post-style-smart: "Smart"
notification-position: "Benachrichtigungen anzeigen"
notification-position-bottom: "Unten"
notification-position-top: "Oben"
disable-via-mobile: "Beitrag nicht als „vom Handy“ markieren"
load-raw-images: "Anhänge in voller Größe laden"
load-remote-media: "Zeige Inhalte von fremden Servern"
save: "Speichern"
saved: "Gespeichert"
search: "Suche"
delete: "Löschen"
loading: "Laden"
ok: "Okay"
cancel: "Abbrechen"
update-available-title: "Aktualisierung verfügbar"
update-available: "Eine neue Version von Misskey ist verfügbar ({newer}, aktuell ist {current}). Lade die Seite neu um die aktuelle Version zu laden"
my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet."
hide-password: "Passwort verbergen"
show-password: "Passwort zeigen"
enter-username: "Kontonamen eingeben"
do-not-use-in-production: "Dies ist eine Entwicklungsversion. Nicht in einer Produktivumgebung verwenden."
user-suspended: "Dieser Nutzer wurde gesperrt."
is-remote-user: "Diese Nutzerinformationen können unvollständig sein."
is-remote-post: "Dies ist ein entfernter Post."
view-on-remote: "Vollständige Infos auf Ursprungsserver anzeigen"
renoted-by: "Renote von {user}"
no-notes: "Keine Beiträge"
turn-on-darkmode: "Dunkles Design"
turn-off-darkmode: "Helles Design"
error:
title: "Allgemeiner Fehler"
retry: "Erneut versuchen"
reversi:
drawn: "Unentschieden"
my-turn: "Du bist am Zug"
opponent-turn: "Dein Gegner ist an der Reihe"
turn-of: "{name}s Zug"
past-turn-of: "Zug von {name}"
won: "{name} hat gewonnen"
black: "Schwarz"
white: "Weiß"
total: "Gesamt"
this-turn: "{count}. Zug"
widgets:
analog-clock: "Analoge Uhr"
profile: "Profil"
calendar: "Kalender"
timemachine: "Kalender (Zeitmaschine)"
activity: "Aktivitäten"
rss: "RSS Leser"
memo: "Notizen"
trends: "Trends"
photo-stream: "Bilder"
posts-monitor: "Beitrags-Aktivität"
slideshow: "Diashow"
version: "Version"
broadcast: "Ankündigungen"
notifications: "Benachrichtigungen"
users: "Empfohlene Benutzer"
polls: "Umfrage"
post-form: "\"Neuer Beitrag\"-Formular"
server: "Server-Info"
nav: "Navigation"
tips: "Tipps"
hashtags: "Hashtags"
queue: "Warteschlange"
dev: "Fehler beim Erstellen der Applikation. Bitte versuche es erneut."
ai-chan-kawaii: "Ai-chan kawaii!"
you: "Du"
auth/views/form.vue:
share-access: "Erlaubst Du <i>{name}</i> auf deinen Account zuzugreifen?"
permission-ask: "Diese Applikation benötigt folgende Berechtigungen:"
cancel: "Abbrechen"
accept: "Zugriff erlauben."
auth/views/index.vue:
loading: "Lädt"
denied: "Autorisierung der Anwendung wurde verweigert."
denied-paragraph: "Diese App kann nicht auf deinen Account zugreifen."
already-authorized: "Diese Anwendung ist bereits autorisiert."
allowed: "Autorisierung der Anwendung wurde erlaubt."
callback-url: "Zur App zurückkehren"
please-go-back: "Bitte gehe zurück zur Anwendung."
error: "Sitzung ist nicht vorhanden."
sign-in: "Bitte melde dich an."
common/views/pages/explore.vue:
pinned-users: "Vorgeschlagen"
popular-users: "Beliebt"
recently-updated-users: "Kürzlich aktiv"
recently-registered-users: "Neue Benutzer"
popular-tags: "Beliebte Tags"
federated: "Aus dem Fediverse"
explore: "{host} erkunden"
users-info: "Momentan sind {users} Nutzer hier registriert"
common/views/components/url-preview.vue:
enable-player: "Player öffnen"
disable-player: "Player schließen"
common/views/components/user-list.vue:
no-users: "Keine Benutzer"
common/views/components/games/reversi/reversi.vue:
matching:
waiting-for: "Warten auf {}"
cancel: "Abbrechen"
common/views/components/games/reversi/reversi.game.vue:
surrender: "Aufgeben"
surrendered: "durch Aufgabe"
is-llotheo: "Der niedrigere gewinnt (Llotheo)"
looped-map: "Spielbrettenden verbinden"
can-put-everywhere: "Setzen ist überall erlaubt"
common/views/components/games/reversi/reversi.index.vue:
title: "Misskey Reversi"
sub-title: "Spiele Reversi mit deinen Freunden!"
invite: "Einladen"
rule: "Spielanleitung"
mode-invite: "Einladen"
all-games: "Alle Spiele"
enter-username: "Bitte gib einen Benutzernamen ein"
game-state:
ended: "Fertig"
common/views/components/games/reversi/reversi.room.vue:
settings-of-the-game: "Spieleinstellungen"
choose-map: "Wähle eine Karte"
random: "Zufällige Auswahl"
black-or-white: "Schwarz/Weiß"
black-is: "Schwarz ist {}"
rules: "Regeln"
is-llotheo: "Der niedrigere gewinnt (Llotheo)"
looped-map: "Spielbrettenden verbinden"
can-put-everywhere: "Setzen ist überall erlaubt"
settings-of-the-bot: "Bot-Einstellungen"
this-game-is-started-soon: "Spiel beginnt gleich"
waiting-for-other: "Warte auf den Gegner"
waiting-for-me: "Warten, bis du bereit bist"
waiting-for-both: "Vorbereiten…"
cancel: "Abbrechen"
ready: "Bereit"
common/views/components/connect-failed.vue:
title: "Verbindung zum Server ist fehlgeschlagen"
description: "Entweder gibt es ein Problem mit deiner Internetverbindung oder der Server ist zur Zeit nicht erreichbar oder wird gewartet. Bitte versuche es später noch einmal."
thanks: "Vielen Dank für das nutzen von Misskey."
troubleshoot: "Problembehandlung"
common/views/components/connect-failed.troubleshooter.vue:
title: "Problembehandlung"
network: "Netzwerkverbindung"
checking-network: "Prüfen der Netzwerkverbindung"
internet: "Internetverbindung"
checking-internet: "Internetverbindung wird getestet"
server: "Serververbindung"
checking-server: "Überprüfung der Server-Verbindung"
finding: "Nach dem Problem suchen"
no-network: "Keine Netzwerkverbindung"
no-network-desc: "Bitte stelle sicher, dass du mit dem Internet verbunden bist."
no-internet: "Keine Internetverbindung"
no-internet-desc: "Bitte vergewissere dich, dass du mit dem Internet verbunden bist."
no-server: "Verbindung mit dem Server nicht möglich"
no-server-desc: "Die Internetverbindung scheint in Ordnung zu sein, aber eine Verbindung mit dem Misskey-Server konnte nicht hergestellt werden. Möglicherweise ist dieser zur Zeit offline oder wird gewartet. Bitte versuche es später noch einmal."
success: "Erfolgreich mit dem Misskey-Server verbunden"
success-desc: "Die Verbindung scheint zu funktionieren. Bitte lade die Seite neu."
flush: "Cache leeren"
set-version: "Version angeben"
common/views/components/media-banner.vue:
sensitive: "Dieser Inhalt ist NSFW"
click-to-show: "Klicke zum den Inhalt anzusehen"
common/views/components/theme.vue:
theme: "Design"
light-theme: "Thema"
dark-theme: "Thema während des Nachtmodus"
light-themes: "Helles Thema"
dark-themes: "Dunkles Thema"
install-a-theme: "Design wird installiert"
theme-code: "Design-Quelltext"
install: "Anwenden"
installed: "\"{}\" wurde installiert"
create-a-theme: "Thema erstellen"
save-created-theme: "Thema speichern"
primary-color: "Primäre Farbe"
secondary-color: "Sekundäre Farbe"
text-color: "Textfarbe"
base-theme: "Basisthema"
base-theme-light: "Hell"
base-theme-dark: "Dunkel"
find-more-theme: "Mehr Designs finden"
theme-name: "Name des Themas"
preview-created-theme: "Vorschau"
invalid-theme: "Thema ist ungültig"
already-installed: "Thema ist bereits installiert"
saved: "Gespeichert"
manage-themes: "Designs verwalten"
builtin-themes: "Standard-Designs"
my-themes: "Meine Designs"
installed-themes: "Installierte Designs"
select-theme: "Design wählen"
uninstall: "Deinstallieren"
uninstalled: "„{}“ wurde deinstalliert"
author: "Autor"
desc: "Beschreibung"
export: "Exportieren"
import: "Importieren"
import-by-code: "oder Quelltext einfügen"
theme-name-required: "Design-Name ist erforderlich"
common/views/components/cw-button.vue:
hide: "Ausblenden"
show: "Mehr"
chars: "{count} Zeichen"
files: "{count} Dateien"
poll: "Umfrage"
common/views/components/messaging.vue:
search-user: "Einen Nutzer suchen"
you: "Du"
no-history: "Keine Chronik"
user: "Benutzer"
group: "Gruppen"
common/views/components/messaging-room.vue:
no-history: "Keine weitere Chronik vorhanden"
new-message: "Neue Nachricht"
common/views/components/messaging-room.form.vue:
input-message-here: "Nachricht hier eingeben"
send: "Senden"
attach-from-local: "Wähle Dateien von deinem PC aus"
attach-from-drive: "Wähle Dateien von deinem Speicher aus"
common/views/components/messaging-room.message.vue:
is-read: "Gelesen"
deleted: "Diese Nachricht wurde gelöscht"
common/views/components/nav.vue:
about: "Über"
stats: "Statistiken"
status: "Status"
wiki: "Wiki"
donors: "Spender"
repository: "Quellcode"
develop: "Entwickler"
feedback: "Feedback"
common/views/components/note-menu.vue:
mention: "Erwähnungen"
detail: "Details"
copy-content: "Inhalt kopieren"
copy-link: "Link kopieren"
favorite: "Diesen Beitrag favorisieren"
unfavorite: "Aus Favoriten entfernen"
watch: "Beobachten"
unwatch: "Nicht mehr beobachten"
pin: "An die Profilseite pinnen"
unpin: "Lösen"
delete: "Löschen"
delete-confirm: "Diesen Beitrag löschen?"
remote: "Auf Quelle anzeigen"
common/views/components/user-menu.vue:
mention: "Erwähnungen"
mute: "Stummschalten"
unmute: "Stummschaltung aufheben"
mute-confirm: "Bist du sicher, dass du diesen Nutzer stummschalten möchtest?"
unmute-confirm: "Stummschaltung für diesen Nutzer aufheben?"
block: "Sperren"
unblock: "Sperrung aufheben"
block-confirm: "Diesen Nutzer wirklich sperren?"
common/views/components/poll.vue:
vote-to: "Stimme für '{}'"
vote-count: "{} Stimmen"
vote: "Abstimmen"
show-result: "Zeige Ergebnis"
voted: "Abgestimmt"
common/views/components/poll-editor.vue:
no-only-one-choice: "Du musst zwei oder mehr Entscheidungen angeben"
choice-n: "Auswahl {}"
remove: "Diese Auswahl entfernen"
add: "+ Eine Auswahl hinzufügen"
destroy: "Diese Abstimmung löschen"
day: "So"
common/views/components/reaction-picker.vue:
choose-reaction: "Wähle eine Reaktion aus"
common/views/components/emoji-picker.vue:
activity: "Aktivität"
common/views/components/signin.vue:
username: "Benutzername"
password: "Passwort"
token: "Token"
signing-in: "Melde an..."
or: "Oder"
common/views/components/signup.vue:
username: "Benutzername"
checking: "Überprüfung..."
available: "Verfügbar"
unavailable: "Nicht verfügbar"
error: "Verbindungsfehler"
invalid-format: "Benutze nur Buchstaben, Zahlen und _"
too-short: "Bitte mindestens ein Zeichen eingeben"
too-long: "Bitte maximal 20 Zeichen verwenden"
password: "Passwort"
password-placeholder: "Wir empfehlen mindestens 8 Zeichen"
weak-password: "Schwaches Passwort"
normal-password: "Normales Passwort"
strong-password: "Starkes Passwort"
retype: "Wiederholen"
retype-placeholder: "Bitte das Passwort erneut eingeben"
password-matched: "OK"
password-not-matched: "Stimmt nicht überein"
recaptcha: "Captcha"
create: "Account erstellen"
some-error: "Die Anmeldung konnte aufgrund eines Fehler nicht abgeschlossen werden. Bitte versuche es erneut."
common/views/components/special-message.vue:
new-year: "Frohes neues Jahr!"
christmas: "Frohe Weihnachten!"
common/views/components/stream-indicator.vue:
connecting: "Verbindung wird hergestellt"
reconnecting: "Erneut verbinden"
connected: "Verbindung hergestellt"
common/views/components/notification-settings.vue:
title: "Benachrichtigungen"
common/views/components/uploader.vue:
waiting: "Warten"
common/views/components/visibility-chooser.vue:
public: "Öffentlich"
home: "Home"
home-desc: "Auf die Startseite posten"
followers: "Folgende"
followers-desc: "Nur für diejenigen sichtbar, die dir folgen"
specified: "Direkt"
specified-desc: "Nur für bestimmte Benutzer sichtbar"
local-public: "Öffentlich (nur lokal)"
local-home: "Home (nur lokal)"
local-followers: "Follower (nur lokal)"
common/views/components/profile-editor.vue:
title: "Dein Profil"
name: "Name"
avatar: "Avatar"
banner: "Banner"
save: "Speichern"
unable-to-process: "Der Vorgang konnte nicht abgeschlossen werden"
export: "Exportieren"
import: "Importieren"
export-targets:
user-lists: "Listen"
enter-password: "Bitte Passwort eingeben"
common/views/components/user-group-editor.vue:
invite: "Einladen"
common/views/components/user-lists.vue:
user-lists: "Listen"
common/views/components/user-groups.vue:
user-groups: "Gruppen"
owned-groups: "Meine Gruppen"
invites: "Einladen"
common/views/widgets/broadcast.vue:
fetching: "Laden"
no-broadcasts: "Keine Broadcasts"
have-a-nice-day: "Schönen Tag!"
next: "Nächster"
common/views/widgets/photo-stream.vue:
title: "Fotostream"
no-photos: "Keine Fotos"
common/views/widgets/posts-monitor.vue:
title: "Beitrags-Aktivität"
toggle: "Sicht umschalten"
common/views/widgets/server.vue:
title: "Serverinformationen"
toggle: "Sicht umschalten"
common/views/widgets/memo.vue:
title: "Notizen"
memo: "Schreib hier!"
save: "Speichern"
desktop:
banner: "Banner"
avatar: "Avatar"
unable-to-process: "Der Vorgang konnte nicht abgeschlossen werden"
desktop/views/components/activity.chart.vue:
total: "Schwarz ... komplett"
notes: "Blau ... Hinweise"
replies: "Rot ... Antworten"
renotes: "Grün ... Anmerkungen"
desktop/views/components/activity.vue:
title: "Aktivität"
toggle: "Sichten umschalten"
desktop/views/components/calendar.vue:
prev: "Vorheriger Monat"
next: "Nächster Monat"
go: "Klicke zur Navigation"
desktop/views/components/choose-file-from-drive-window.vue:
upload: "Dateien von deinem PC hochladen"
cancel: "Abbrechen"
ok: "OK"
choose-prompt: "Wähle eine Datei aus"
desktop/views/components/choose-folder-from-drive-window.vue:
cancel: "Abbrechen"
ok: "OK"
choose-prompt: "Wähle einen Ordner"
desktop/views/components/crop-window.vue:
skip: "Zuschneiden überspringen"
cancel: "Abbrechen"
ok: "OK"
desktop/views/components/drive-window.vue:
used: "benutzt"
desktop/views/components/drive.file.vue:
avatar: "Avatar"
banner: "Banner"
contextmenu:
rename: "Umbenennen"
copy-url: "URL kopieren"
download: "Download"
set-as-avatar: "Als Avatar festlegen"
set-as-banner: "Setze als Banner"
open-in-app: "In der App öffnen"
add-app: "App hinzufügen"
rename-file: "Datei umbennen"
input-new-file-name: "Gib den neuen Dateinamen an"
copied: "Kopieren erfolgreich"
copied-url-to-clipboard: "URL wurde in die Zwischenablage kopiert"
desktop/views/components/drive.folder.vue:
unable-to-process: "Der Vorgang konnte nicht abgeschlossen werden"
circular-reference-detected: "Das Zielverzeichnis ist innerhalb des Verzeichnisses, dass du verschieben möchtest"
unhandled-error: "Unbekannter Fehler"
contextmenu:
move-to-this-folder: "Verschiebe in diesen Ordner"
show-in-new-window: "In einem neuen Fenster anzeigen"
rename: "Umbenennen"
rename-folder: "Ordner umbenennen"
input-new-folder-name: "Namen für neuen Ordner eingeben"
desktop/views/components/drive.vue:
search: "Suchen"
empty-draghover: "Herzlich Willkommen!"
empty-drive: "Dein Speicher ist leer"
empty-drive-description: "Du kannst rechts klicken und \"Datei hochladen\" auswählen oder eine Datei per Drag and Drop auf das Fenster ziehen."
empty-folder: "Dieser Ordner ist leer"
unable-to-process: "Der Vorgang konnte nicht beendet werden"
circular-reference-detected: "Das Zielverzeichnis ist innerhalb des Verzeichnisses, dass du verschieben möchtest"
unhandled-error: "Unbekannter Fehler"
url-upload: "Von einer URL hochladen"
url-of-file: "URL der Datei, welche du hochladen möchtest"
url-upload-requested: "Upload angefordert"
may-take-time: "Es kann eine Weile dauern, bis der Upload fertiggestellt ist."
create-folder: "Ein Verzeichnis erstellen"
folder-name: "Ordnername"
contextmenu:
create-folder: "Ein Verzeichnis erstellen"
upload: "Eine Datei hochladen"
url-upload: "Von einer URL hochladen"
desktop/views/components/followers.vue:
empty: "Dir scheint niemand zu folgen."
desktop/views/components/following.vue:
empty: "Du folgst niemanden"
desktop/views/components/home.vue:
done: "Beenden"
add-widget: "Widget hinzufügen:"
add: "Hinzufügen"
desktop/views/input-dialog.vue:
cancel: "Abbrechen"
ok: "OK"
desktop/views/components/note-detail.vue:
private: "Dieser Beitrag ist privat"
deleted: "Dieser Beitrag wurde entfernt"
location: "Ort"
renote: "Anmerkung"
add-reaction: "Reaktion hinzufügen"
desktop/views/components/note.vue:
reply: "Antworten"
renote: "Anmerkung"
detail: "Details"
private: "Dieser Beitrag ist privat"
deleted: "Dieser Beitrag wurde entfernt"
desktop/views/components/notes.vue:
error: "Laden fehlgeschlagen."
retry: "Erneut versuchen"
desktop/views/components/notifications.vue:
empty: "Keine Benachrichtigungen"
desktop/views/components/post-form.vue:
posted: "Gepostet!"
replied: "Geantwortet!"
reposted: "Weitergesagt!"
note-failed: "Anmerkung fehlgeschlagen"
reply-failed: "Antwort fehlgeschlagen"
renote-failed: "Anmerkung fehlgeschlagen"
desktop/views/components/post-form-window.vue:
note: "Neuer Beitrag"
reply: "Antworten"
attaches: "{} Medien hinzugefügt"
uploading-media: "Lade {} Medien hoch"
desktop/views/components/progress-dialog.vue:
waiting: "Warten"
desktop/views/components/renote-form.vue:
quote: "Zitieren..."
cancel: "Abbrechen"
renote: "Anmerkung"
reposting: "Weitersagen..."
success: "Weitergesagt!"
failure: "Weitersagen fehlgeschlagen"
desktop/views/components/renote-form-window.vue:
title: "Bist du dir sicher, dass du das weitersagen willst?"
desktop/views/components/settings.2fa.vue:
url: "https://www.google.de/intl/de/landing/2step/"
register: "Ein Gerät registrieren"
already-registered: "Das Gerät wurde bereits registriert"
unregister: "Abschalten"
unregistered: "Zwei-Faktor-Authentifizierung wurde deaktiviert."
enter-password: "Bitte Passwort eingeben"
token: "Token"
common/views/components/api-settings.vue:
enter-password: "Bitte Passwort eingeben"
console:
parameter: "Parameter"
send: "Senden"
common/views/components/drive-settings.vue:
in-use: "benutzt"
stats: "Statistiken"
common/views/components/mute-and-block.vue:
save: "Speichern"
desktop/views/components/sub-note-content.vue:
private: "Dieser Beitrag ist privat"
deleted: "Dieser Beitrag wurde entfernt"
poll: "Umfrage"
desktop/views/components/settings.tags.vue:
add: "Hinzufügen"
save: "Speichern"
desktop/views/components/timeline.vue:
home: "Home"
local: "Lokal"
global: "Global"
list: "Listen"
desktop/views/components/ui.header.account.vue:
profile: "Dein Profil"
lists: "Listen"
groups: "Gruppen"
desktop/views/components/ui.header.nav.vue:
game: "Spielen"
desktop/views/components/ui.header.notifications.vue:
title: "Benachrichtigungen"
desktop/views/components/ui.header.post.vue:
post: "Einen neuen Post erstellen"
desktop/views/components/ui.header.search.vue:
placeholder: "Suchen"
desktop/views/components/users-list.vue:
fetching: "Lade…"
admin/views/dashboard.vue:
drive: "Drive"
admin/views/abuse.vue:
details: "Details"
remove-report: "Löschen"
admin/views/instance.vue:
recaptcha-preview: "Vorschau"
invite: "Einladen"
save: "Speichern"
saved: "Gespeichert"
test-email: "Test"
admin/views/charts.vue:
drive: "Drive"
admin/views/drive.vue:
origin:
local: "Lokal"
delete: "Löschen"
admin/views/users.vue:
username: "Benutzername"
users:
origin:
local: "Lokal"
admin/views/emoji.vue:
add-emoji:
add: "Hinzufügen"
emojis:
remove: "Löschen"
admin/views/announcements.vue:
save: "Speichern"
remove: "Löschen"
add: "Hinzufügen"
saved: "Gespeichert"
admin/views/federation.vue:
status: "Status"
save: "Speichern"
desktop/views/pages/note.vue:
prev: "Vorheriger Kommentar"
next: "Nächster Kommentar"
desktop/views/pages/selectdrive.vue:
title: "Wähle Datei(en) aus"
ok: "OK"
cancel: "Abbrechen"
desktop/views/pages/user-list.users.vue:
username: "Benutzername"
desktop/views/pages/user/user.followers-you-know.vue:
loading: "Laden"
desktop/views/pages/user/user.friends.vue:
loading: "Laden"
desktop/views/pages/user/user.photos.vue:
loading: "Laden"
no-photos: "Keine Fotos"
desktop/views/pages/user/user.header.vue:
month: "Mo"
day: "So"
desktop/views/widgets/notifications.vue:
title: "Benachrichtigungen"
desktop/views/widgets/polls.vue:
title: "Umfrage"
nothing: "Keine Benachrichtigungen"
desktop/views/widgets/trends.vue:
nothing: "Keine Benachrichtigungen"
mobile/views/components/drive.vue:
used: "benutzt"
folder-name: "Ordnername"
url-prompt: "URL der Datei, welche du hochladen möchtest"
mobile/views/components/drive.file-detail.vue:
download: "Download"
rename: "Umbenennen"
mobile/views/components/note.vue:
private: "Dieser Beitrag ist privat"
deleted: "Dieser Beitrag wurde entfernt"
location: "Ort"
mobile/views/components/note-detail.vue:
reply: "Antworten"
private: "Dieser Beitrag ist privat"
deleted: "Dieser Beitrag wurde entfernt"
location: "Ort"
mobile/views/components/notifications.vue:
empty: "Keine Benachrichtigungen"
mobile/views/components/sub-note-content.vue:
private: "Dieser Beitrag ist privat"
deleted: "Dieser Beitrag wurde entfernt"
poll: "Umfrage"
mobile/views/components/ui.nav.vue:
notifications: "Benachrichtigungen"
search: "Suchen"
user-lists: "Listen"
user-groups: "Gruppen"
game: "Spielen"
about: "Über"
mobile/views/pages/drive.vue:
contextmenu:
upload: "Eine Datei hochladen"
create-folder: "Ein Verzeichnis erstellen"
mobile/views/pages/home.vue:
home: "Home"
local: "Lokal"
global: "Global"
mobile/views/pages/widgets.vue:
add-widget: "Hinzufügen"
customization-tips: "Anpassungs-Tipps"
mobile/views/pages/widgets/activity.vue:
activity: "Aktivität"
mobile/views/pages/note.vue:
prev: "Vorheriger Kommentar"
next: "Nächster Kommentar"
mobile/views/pages/search.vue:
search: "Suchen"
mobile/views/pages/notifications.vue:
notifications: "Benachrichtigungen"
mobile/views/pages/user/home.vue:
activity: "Aktivität"
keywords: "Schlagwörter"
mobile/views/pages/user/home.photos.vue:
no-photos: "Keine Fotos"
deck:
home: "Home"
local: "Lokal"
global: "Global"
notifications: "Benachrichtigungen"
list: "Listen"
rename: "Umbenennen"
deck/deck.user-column.vue:
following: "Folgen"
followers: "Folgende"
images: "Bilder"
activity: "Aktivität"
timeline: "Zeitleiste"
pinned-notes: "Angeheftete Beiträge"
docs:
edit-this-page-on-github: "Hast Du einen Fehler gefunden oder Lust, diese Dokumentation zu verbessern?"
edit-this-page-on-github-link: "Seite auf GitHub bearbeiten!"
dev/views/index.vue:
manage-apps: "Anwendungen verwalten"
dev/views/apps.vue:
manage-apps: "Anwendungen verwalten"
create-app: "Anwendung erstellen"
app-missing: "Keine Anwendungen"
dev/views/new-app.vue:
create-app: "Erstelle Anwendung"
app-name: "Name der Anwendung"
app-name-desc: "Der Name der Anwendung"
app-overview: "Beschreibung der Anwendung"
callback-url: "Callback-URL (optional)"
callback-url-desc: "Die URL, auf die nach erfolgreicher Authentifizierung umgeleitet werden soll."
authority: "Berechtigungen"
authority-desc: "Nur die hier eingetragenen Berechtigungen, werden per API zur Verfügung stehen."
authority-warning: "Dies kann auch nach dem erstellen der Anwendung geändert werden, allerdings werden dann alle bisher generierten Token ungültig."
pages:
pin-this-page: "An die Profilseite pinnen"
unpin-this-page: "Lösen"
like: "Gefällt mir"
blocks:
post: "\"Neuer Beitrag\"-Formular"
script:
categories:
random: "Zufällige Auswahl"
list: "Listen"
blocks:
_join:
arg1: "Listen"
random: "Zufällige Auswahl"
_randomPick:
arg1: "Listen"
_dailyRandomPick:
arg1: "Listen"
_seedRandomPick:
arg2: "Listen"
_pick:
arg1: "Listen"
_listLen:
arg1: "Listen"
types:
array: "Listen"
room:
save: "Speichern"
saved: "Gespeichert"
furnitures:
moon: "Mond"
bin: "Papierkorb"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,19 +14,19 @@ const merge = (...args) => args.reduce((a, c) => ({
}), {});
const languages = [
'cs-CZ',
'da-DK',
'de-DE',
//'cs-CZ',
//'da-DK',
//'de-DE',
'en-US',
'es-ES',
'fr-FR',
//'fr-FR',
'ja-JP',
'ja-KS',
//'ja-KS',
'ko-KR',
'nl-NL',
'pl-PL',
'zh-CN',
'zh-TW',
//'nl-NL',
//'pl-PL',
//'zh-CN',
//'zh-TW',
];
const primaries = {

View File

@ -1,6 +0,0 @@
---
meta:
lang: "Italiano"
common:
misskey: "A ⭐ of the fediverse"
about-title: "A ⭐ of the fediverse."

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,701 +1 @@
---
meta:
lang: "Nederlands"
common:
misskey: "Deel alles met anderen die ook Misskey gebruiken."
about-title: "Een ster van het fediverse"
about: "Bedankt voor het ontdekken van Misskey. Misskey is een <b>gedecentraliseerd microblogging platform</b> geboren op aarde. Omdat het bestaat binnen het Fediverse (een georganiseerd universum van verschillende sociale mediaplatformen), staat het verbonden met andere sociale medieplatformen. Neem een pauze van de stedelijke drukte, en duik in het nieuwe intenet?"
intro:
title: "Wat is Misskey?"
about: "Misskey is een open source <b>gedecentraliseerd blogplatform</b>. Het heeft een gesofisticeerde, volledig aanpasbare gebruikersinterface, uitgebreide reactiemogelijkheden voor posts, gratis geïntegreerd bestandsoplagbeheer en andere geavanceerde mogelijkheden. Daarnaast staat Misskey verbonden aan een netwerksysteem genaam het \"Fediverse\", hiermee kunnen we communiceren met andere gebruikers op andere SNSs. Dit betekent dat wanneer je iets post het niet enkel verstuurd wordt naar andere Misskey gebruikers, maar ook naar gebruikers op Mastodon en Pleroma. Stel je voor dat een planeet een radiosignaal verzendt naar een andere planeet als manier van communiceren."
features: "Kenmerken"
rich-contents: "Bericht"
rich-contents-desc: "Post jouw idee, hot topic, wat je ook maar wil delen. Maak jouw teksten aantrekkelijk met je favoriete foto's, verzend bestanden, zelfs video's, of maak een poll. Dit zijn enkele van de mogelijkheden die Misskey aanbiedt!"
reaction: "Reactie"
reaction-desc: "Dé makkelijkste manier om jouw gevoelens uit te drukken. Met Misskey kan je verschillende reacties toevoegen aan jouw posts. Andere SNSs hebben enkel maar een \"vind ik leuk\" reactie."
ui: "Interface"
ui-desc: "Niet één UI past nij iedereen. Daarom heeft Misskey een uitgebreide keuze om de UI naar jouw hand te zetten. Je kan jouw nieuwe thuis zo origineel maken als je zelf wil door jouw tijdslijn aan te passen door widgets te verplaatsen en hun look te veranderen. Zo maak je van Misskey jouw eigen stek."
drive: "Drive"
drive-desc: "Wil je een foto posten die je reeds het geüpload? Wens je georganiseerde map met zelfgekozen naam maken voor al jouw bestanden? De beste oplossing voor jou is Misskey Drive. Dit maakt het supermakkelijk om jouw bestanden online te delen."
application-authorization: "Geauthoriseerde applicaties"
close: "Sluiten"
do-not-copy-paste: "Gelieve de code hier niet in te geven of te plakken. De account kan gecompromiseerd zijn."
load-more: "Laad meer resultaten"
enter-password: "Voer het wachtwoord in"
2fa: "Tweestapsverificatie"
customize-home: "Layout aanpassen"
featured-notes: "Uitgelicht"
dark-mode: "Donker thema"
signin: "Aanmelden"
signup: "Registreren"
signout: "Afmelden"
reload-to-apply-the-setting: "Herlaad de pagina om je aanpassingen te bekijken. Wil je de pagina nu herladen?"
fetching-as-ap-object: "Verzenden naar Fediverse"
unfollow-confirm: "Wil stoppen met {name} te volgen?"
delete-confirm: "Ben je zeker dat je dit bericht wil verwijderen?"
signin-required: "Gelieve in te loggen"
notification-type: "Notificatietype"
notification-types:
all: "Alle"
pollVote: "Stemmen"
follow: "Volgend"
receiveFollowRequest: "Volgverzoeken"
reply: "Beantwoorden"
quote: "Bron"
mention: "Vermeldingen"
reaction: "Reactie"
got-it: "Ik snap het!"
customization-tips:
title: "Aanpassingstips"
gotit: "Ik snap het!"
notification:
file-uploaded: "Je bestand is geüpload"
message-from: "Bericht van {}:"
reversi-invited: "Uitgenodigd voor spel"
notified-by: "Bemerkt door: {}"
reply-from: "Antwoord van: {}"
quoted-by: "Geciteerd door: {}"
time:
unknown: "onbekend"
future: "toekomstig"
just_now: "zojuist"
seconds_ago: "{}s geleden"
minutes_ago: "{}m geleden"
hours_ago: "{}u geleden"
days_ago: "{}d geleden"
weeks_ago: "{}week/weken geleden"
months_ago: "{}maand(en) geleden"
years_ago: "{}jaar geleden"
month-and-day: "{day} {month}"
trash: "Prullenbak"
drive: "Drive"
pages: "Pagina's"
messaging: "Gesprekken"
home: "Startpagina"
deck: "Deck"
timeline: "Tijdlijn"
followers: "Volgers"
favorites: "Deze notitie toevoegen aan favorieten"
permissions:
"write:votes": "Stemmen"
post-form:
submit: "Bericht"
reply: "Beantwoorden"
add-visible-user: "Gebruiker toevoegen"
weekday-short:
sunday: "Z"
monday: "M"
tuesday: "D"
wednesday: "W"
thursday: "D"
friday: "V"
saturday: "Z"
reactions:
like: "Leuk"
love: "Geweldig"
laugh: "Grappig"
hmm: "Eh...?"
surprise: "Wauw"
congrats: "Gefeliciteerd!"
angry: "Boos"
confused: "Verward"
pudding: "Pudding"
note-visibility:
home: "Startpagina"
followers: "Volgers"
_settings:
profile: "Je profiel"
notification: "Meldingen"
password: "Wachtwoord"
reactions: "Reactie"
deck-column-align-center: "Centreren"
deck-column-align-left: "Links"
timeline: "Tijdlijn"
navbar-position-left: "Links"
search: "Zoeken"
delete: "Verwijderen"
loading: "Bezig met laden"
update-available: "Er is een nieuwe versie van Misskey beschikbaar: {newer} (de huidige versie is {current}). Herlaad de pagina om de update toe te passen."
my-token-regenerated: "Je sleutel is gegenereerd; je wordt nu uitgelogd."
widgets:
profile: "Je profiel"
activity: "Activiteit"
trends: "Populair"
photo-stream: "Fotostream"
notifications: "Meldingen"
users: "Aanbevolen gebruikers"
server: "Serverinformatie"
you: "Jij"
auth/views/form.vue:
cancel: "Annuleren"
auth/views/index.vue:
loading: "Bezig met laden"
common/views/components/games/reversi/reversi.vue:
matching:
cancel: "Annuleren"
common/views/components/games/reversi/reversi.room.vue:
cancel: "Annuleren"
common/views/components/connect-failed.vue:
title: "Verbinden met server mislukt"
description: "Er is een probleem met je internetverbinding, de server ligt plat of er wordt aan gewerkt. {Probeer} het later opnieuw."
thanks: "Bedankt voor het gebruiken van Misskey."
troubleshoot: "Probleemoplossing"
common/views/components/connect-failed.troubleshooter.vue:
title: "Probleemoplossing"
network: "Netwerkverbinding"
checking-network: "Bezig met controleren van netwerkverbinding"
internet: "Internetverbinding"
checking-internet: "Bezig met controleren van internetverbinding"
server: "Serververbinding"
checking-server: "Bezig met controleren van serververbinding"
finding: "Bezig met vaststellen van probleem"
no-network: "Er is geen internetverbinding"
no-network-desc: "Zorg ervoor dat je verbonden bent met een netwerk."
no-internet: "Er is geen internetverbinding"
no-internet-desc: "Zorg ervoor dat je verbonden bent met het internet."
no-server: "Verbinden met Misskey-server mislukt"
no-server-desc: "De netwerkverbinding van je computer is goed, maar er kan geen verbinding worden gemaakt met de Misskey-server. Het kan dat de server plat ligt of dat eraan wordt gewerkt. Probeer het later opnieuw."
success: "Verbonden met de Misskey-server"
success-desc: "Het verbinden lijkt te lukken. Herlaad de pagina."
flush: "Cache leegmaken"
set-version: "Versie opgeven"
common/views/components/theme.vue:
desc: "Omschrijving"
common/views/components/messaging.vue:
search-user: "Gebruiker zoeken"
you: "Jij"
no-history: "Geen geschiedenis"
user: "Gebruiker"
common/views/components/messaging-room.vue:
no-history: "Er is geen verdere geschiedenis"
new-message: "Nieuw bericht"
common/views/components/messaging-room.form.vue:
input-message-here: "Voer hier je bericht in"
send: "Versturen"
attach-from-local: "Bestanden bijvoegen van je computer"
attach-from-drive: "Bestanden bijvoegen van je Drive"
common/views/components/messaging-room.message.vue:
is-read: "Gelezen"
deleted: "Dit bericht is verwijderd"
common/views/components/nav.vue:
about: "Over"
stats: "Statistieken"
status: "Status"
donors: "Donateurs"
repository: "Broncode"
develop: "Ontwikkelaars"
feedback: "Feedback"
common/views/components/note-menu.vue:
favorite: "Deze notitie toevoegen aan favorieten"
pin: "Vastmaken aan profielpagina"
delete: "Verwijderen"
remote: "Origineel tonen"
common/views/components/poll.vue:
vote-to: "Stemmen op '{}'"
vote-count: "{} stemmen"
vote: "Stemmen"
show-result: "Resultaten tonen"
voted: "Gestemd"
common/views/components/poll-editor.vue:
no-only-one-choice: "Je moet twee of meer keuzes invoeren."
choice-n: "Keuze {}"
remove: "Deze keuze verwijderen"
add: "+ Keuze toevoegen"
destroy: "Deze peiling vernietigen"
day: "Z"
common/views/components/reaction-picker.vue:
choose-reaction: "Kies een reactie"
common/views/components/emoji-picker.vue:
activity: "Activiteit"
common/views/components/signin.vue:
username: "Gebruikersnaam"
password: "Wachtwoord"
token: "Sleutel"
signing-in: "Bezig met inloggen..."
common/views/components/signup.vue:
username: "Gebruikersnaam"
checking: "Bezig met controleren..."
available: "Beschikbaar"
unavailable: "Niet beschikbaar"
error: "Netwerkfout"
invalid-format: "Gebruik alleen letters, cijfers en -."
too-short: "Voer minimaal 1 teken in!"
too-long: "Voer maximaal 20 tekens in."
password: "Wachtwoord"
password-placeholder: "Wij raden aan meer dan 8 tekens te gebruiken."
weak-password: "Zwak"
normal-password: "'t Ken net"
strong-password: "Sterk"
retype: "Opnieuw invoeren"
retype-placeholder: "Wachtwoord bevestigen"
password-matched: "Oké"
password-not-matched: "Komt niet overeen"
recaptcha: "Verifiëren"
create: "Account creëren"
some-error: "Het creëren van een account is mislukt. Probeer het opnieuw."
common/views/components/special-message.vue:
new-year: "Gelukkig nieuwjaar!"
christmas: "Fijne kerstdagen!"
common/views/components/stream-indicator.vue:
connecting: "Bezig met verbinden"
reconnecting: "Bezig met herverbinden"
connected: "Verbonden"
common/views/components/notification-settings.vue:
title: "Meldingen"
common/views/components/github-setting.vue:
detail: "Details bekijken..."
common/views/components/discord-setting.vue:
detail: "Details bekijken..."
common/views/components/uploader.vue:
waiting: "Bezig met wachten"
common/views/components/visibility-chooser.vue:
home: "Startpagina"
followers: "Volgers"
common/views/components/profile-editor.vue:
title: "Je profiel"
name: "Naam"
avatar: "Gebruikersafbeelding"
banner: "Omslagfoto"
unable-to-process: "De operatie kan niet worden voltooid."
export-targets:
following-list: "Volgend"
user-lists: "Lijsten"
enter-password: "Voer het wachtwoord in"
common/views/components/user-list-editor.vue:
users: "Gebruiker"
add-user: "Gebruiker toevoegen"
common/views/components/user-lists.vue:
user-lists: "Lijsten"
common/views/widgets/broadcast.vue:
fetching: "Bezig met ophalen"
no-broadcasts: "Geen uitzendingen"
have-a-nice-day: "Fijne dag!"
next: "Volgende"
common/views/widgets/photo-stream.vue:
title: "Fotostream"
no-photos: "Geen foto's"
common/views/widgets/posts-monitor.vue:
toggle: "Schakelen tussen weergaven"
common/views/widgets/server.vue:
title: "Serverinformatie"
toggle: "Schakelen tussen weergaven"
common/views/pages/follow.vue:
signed-in-as: "Ingelogd als {}"
follow: "Volgend"
desktop:
banner: "Omslagfoto"
avatar: "Gebruikersafbeelding"
unable-to-process: "De operatie kan niet worden voltooid."
desktop/views/components/activity.chart.vue:
total: "Zwart ... totaal"
notes: "Blauw ... notities"
replies: "Rood ... antwoorden"
renotes: "Groen ... gedeelde notities"
desktop/views/components/activity.vue:
title: "Activiteit"
toggle: "Schakelen tussen weergaven"
desktop/views/components/calendar.vue:
prev: "Vorige maand"
next: "Volgende maand"
go: "Klik om te navigeren"
desktop/views/components/choose-file-from-drive-window.vue:
upload: "Bestanden uploaden van je computer"
cancel: "Annuleren"
ok: "Oké"
choose-prompt: "Kies een bestand"
desktop/views/components/choose-folder-from-drive-window.vue:
cancel: "Annuleren"
ok: "Oké"
choose-prompt: "Kies een map"
desktop/views/components/crop-window.vue:
skip: "Bijsnijden overslaan"
cancel: "Annuleren"
ok: "Oké"
desktop/views/components/drive-window.vue:
used: "gebruikt"
desktop/views/components/drive.file.vue:
avatar: "Gebruikersafbeelding"
banner: "Omslagfoto"
contextmenu:
rename: "Naam wijzigen"
copy-url: "URL kopiëren"
download: "Downloaden"
set-as-avatar: "Instellen als gebruikersafbeelding"
set-as-banner: "Instellen als omslagfoto"
open-in-app: "Openen in app"
add-app: "App toevoegen"
rename-file: "Bestandsnaam wijzigen"
input-new-file-name: "Voer een nieuwe naam in"
copied: "Gekopieerd"
copied-url-to-clipboard: "URL gekopieerd naar klembord"
desktop/views/components/drive.folder.vue:
unable-to-process: "De operatie kan niet worden voltooid."
circular-reference-detected: "De bestemmingsmap is een submap van de map die je wilt verplaatsen."
unhandled-error: "Onbekende fout"
contextmenu:
move-to-this-folder: "Verplaatsen naar deze map"
show-in-new-window: "Openen in nieuw venster"
rename: "Naam wijzigen"
rename-folder: "Mapnaam wijzigen"
input-new-folder-name: "Voer een nieuwe naam in"
desktop/views/components/drive.vue:
search: "Zoeken"
empty-draghover: "Welkom!"
empty-drive: "Je schijf is leeg"
empty-drive-description: "Je kunt ook uploaden door te klikken met de rechtermuisknop en te kiezen voor \"Bestand uploaden\" of door een bestand naar dit venster te slepen."
empty-folder: "Deze map is leeg"
unable-to-process: "De operatie kan niet worden voltooid."
circular-reference-detected: "De bestemmingsmap is een submap van de te verplaatsen map."
unhandled-error: "Onbekende fout"
url-upload: "Uploaden via URL"
url-of-file: "URL van het te uploaden bestand"
url-upload-requested: "Uploadverzoek"
may-take-time: "Het kan even duren voordat het uploaden voltooid is."
create-folder: "Map creëren"
folder-name: "Mapnaam"
contextmenu:
create-folder: "Map creëren"
upload: "Bestand uploaden"
url-upload: "Uploaden via URL"
desktop/views/components/followers-window.vue:
followers: "Volgers van {}"
desktop/views/components/followers.vue:
empty: "Het lijkt erop dat je geen volgers hebt."
desktop/views/components/following-window.vue:
following: "Volgend {}"
desktop/views/components/following.vue:
empty: "Je volgt niemand."
desktop/views/components/game-window.vue:
game: "Othello"
desktop/views/components/home.vue:
done: "Versturen"
add-widget: "Widget toevoegen:"
add: "Toevoegen"
desktop/views/input-dialog.vue:
cancel: "Annuleren"
ok: "Oké"
desktop/views/components/note-detail.vue:
private: "(dit bericht is privé)"
location: "Locatie"
add-reaction: "Reactie"
desktop/views/components/note.vue:
reply: "Beantwoorden"
add-reaction: "Reactie"
private: "(dit bericht is privé)"
desktop/views/components/notes.vue:
error: "Laden mislukt."
retry: "Opnieuw proberen"
desktop/views/components/notifications.vue:
empty: "Geen meldingen"
desktop/views/components/post-form.vue:
posted: "Geplaatst!"
replied: "Beantwoord!"
reposted: "Hergeplaatst!"
note-failed: "Noteren mislukt"
reply-failed: "Beantwoorden mislukt"
renote-failed: "Renote mislukt"
desktop/views/components/post-form-window.vue:
note: "Nieuwe notitie"
reply: "Beantwoorden"
attaches: "{} media bijgevoegd"
uploading-media: "Bezig met uploaden van media {}"
desktop/views/components/progress-dialog.vue:
waiting: "Bezig met wachten"
desktop/views/components/renote-form.vue:
quote: "Citeren..."
cancel: "Annuleren"
reposting: "Bezig met herplaatsen..."
success: "Hergeplaatst!"
failure: "Renote mislukt"
desktop/views/components/renote-form-window.vue:
title: "Weet je zeker dat je deze notitie wilt renoten?"
desktop/views/components/settings.2fa.vue:
intro: "Als je verificatie in twee stappen instelt, dan heb je niet alleen een wachtwoord nodig bij het inloggen, maar ook een geregistreerd fysiek apparaat (zoals je smartphone). Dit verhoogt de veiligheid. "
detail: "Details bekijken..."
url: "https://www.google.com/landing/2step/"
caution: "Als je geen toegang meer hebt tot je apparaat, dan kun je niet meer verbinden met Misskey!"
register: "Apparaat registreren"
already-registered: "Er is al een apparaat geregistreerd"
unregister: "Uitschakelen"
unregistered: "Authenticatie in twee stappen is uitgeschakeld."
enter-password: "Voer het wachtwoord in"
authenticator: "Installeer eerst Google Authenticator op je apparaat:"
howtoinstall: "Hoe installeer ik dit?"
token: "Sleutel"
scan: "Scan daarna de QR-code:"
done: "Voer de op je apparaat getoonde sleutel in:"
submit: "Versturen"
success: "Instellen voltooid!"
failed: "Instellen mislukt. Zorg ervoor dat de sleutel juist is."
info: "Vanaf nu moet je ook de op je apparaat getoonde sleutel tonen bij het inloggen op Misskey."
common/views/components/api-settings.vue:
enter-password: "Voer het wachtwoord in"
console:
parameter: "Parameters"
send: "Versturen"
common/views/components/drive-settings.vue:
in-use: "gebruikt"
stats: "Statistieken"
default-upload-folder-name: "Map(pen)"
desktop/views/components/sub-note-content.vue:
private: "(dit bericht is privé)"
poll: "Peilingen"
desktop/views/components/settings.tags.vue:
add: "Toevoegen"
desktop/views/components/timeline.vue:
home: "Startpagina"
local: "Lokaal"
global: "Algemeen"
list: "Lijsten"
desktop/views/components/ui.header.account.vue:
profile: "Je profiel"
lists: "Lijsten"
desktop/views/components/ui.header.nav.vue:
game: "Othello spelen"
desktop/views/components/ui.header.notifications.vue:
title: "Meldingen"
desktop/views/components/ui.header.post.vue:
post: "Nieuw bericht opstellen"
desktop/views/components/ui.header.search.vue:
placeholder: "Zoeken"
desktop/views/components/user-preview.vue:
notes: "Berichten"
following: "Volgend"
followers: "Volgers"
desktop/views/components/users-list.vue:
all: "Alle"
iknow: "die ik ken"
fetching: "Bezig met laden…"
desktop/views/components/users-list-item.vue:
followed: "Volgt jou"
desktop/views/components/window.vue:
popout: "Uitvouwen"
close: "Sluiten"
admin/views/index.vue:
users: "Gebruiker"
admin/views/dashboard.vue:
notes: "Bericht"
drive: "Drive"
admin/views/abuse.vue:
remove-report: "Verwijderen"
admin/views/charts.vue:
notes: "Bericht"
users: "Gebruiker"
drive: "Drive"
admin/views/drive.vue:
origin:
local: "Lokaal"
delete: "Verwijderen"
admin/views/users.vue:
username: "Gebruikersnaam"
users:
title: "Gebruiker"
state:
all: "Alle"
origin:
local: "Lokaal"
admin/views/emoji.vue:
add-emoji:
add: "Toevoegen"
emojis:
remove: "Verwijderen"
admin/views/announcements.vue:
remove: "Verwijderen"
add: "Toevoegen"
admin/views/federation.vue:
notes: "Bericht"
users: "Gebruiker"
followers: "Volgers"
status: "Status"
states:
all: "Alle"
desktop/views/pages/welcome.vue:
timeline: "Tijdlijn"
desktop/views/pages/note.vue:
prev: "Vorige notitie"
next: "Volgende notitie"
desktop/views/pages/selectdrive.vue:
title: "Bestand(en) kiezen"
ok: "Oké"
cancel: "Annuleren"
upload: "Bestanden uploaden van je PC"
desktop/views/pages/user-list.users.vue:
users: "Gebruiker"
add-user: "Gebruiker toevoegen"
username: "Gebruikersnaam"
desktop/views/pages/user/user.followers-you-know.vue:
title: "Volgers die je kent"
loading: "Bezig met laden"
no-users: "Geen gebruikers"
desktop/views/pages/user/user.friends.vue:
title: "Frequent beantwoord"
loading: "Bezig met laden"
no-users: "Geen gebruikers"
desktop/views/pages/user/user.photos.vue:
title: "Foto's"
loading: "Bezig met laden"
no-photos: "Geen foto's"
desktop/views/pages/user/user.header.vue:
posts: "Bericht"
following: "Volgend"
followers: "Volgers"
month: "M"
day: "Z"
follows-you: "Volgt jou"
desktop/views/pages/user/user.timeline.vue:
default: "Berichten"
with-replies: "Berichten en antwoorden"
with-media: "Media"
desktop/views/widgets/notifications.vue:
title: "Meldingen"
desktop/views/widgets/polls.vue:
title: "Peilingen"
refresh: "Anderen tonen"
nothing: "Niks"
desktop/views/widgets/post-form.vue:
title: "Bericht"
note: "Bericht"
desktop/views/widgets/profile.vue:
update-banner: "Klik om je omslagfoto te wijzigen"
update-avatar: "Klik om je gebruikersafbeelding te wijzigen"
desktop/views/widgets/trends.vue:
title: "Populair"
refresh: "Anderen tonen"
nothing: "Niks"
desktop/views/widgets/users.vue:
title: "Aanbevolen gebruikers"
refresh: "Anderen tonen"
no-one: "Niemand"
mobile/views/components/drive.vue:
used: "gebruikt"
folder-count: "Map(pen)"
count-separator: ", "
file-count: "Bestand(en)"
nothing-in-drive: "Niks"
folder-is-empty: "Deze map is leeg"
folder-name: "Mapnaam"
url-prompt: "URL van het te uploaden bestand"
mobile/views/components/drive-file-chooser.vue:
select-file: "Kies een bestand"
mobile/views/components/drive-folder-chooser.vue:
select-folder: "Kies een map"
mobile/views/components/drive.file-detail.vue:
download: "Downloaden"
rename: "Naam wijzigen"
move: "Verplaatsen"
hash: "Hash (md5)"
common/views/components/follow-button.vue:
follow: "Volgend"
mobile/views/components/note.vue:
private: "(dit bericht is privé)"
location: "Locatie"
mobile/views/components/note-detail.vue:
reply: "Beantwoorden"
reaction: "Reactie"
private: "(dit bericht is privé)"
location: "Locatie"
mobile/views/components/notifications.vue:
empty: "Geen meldingen"
mobile/views/components/sub-note-content.vue:
private: "(dit bericht is privé)"
media-count: "{} media"
poll: "Peiling"
mobile/views/components/ui.nav.vue:
timeline: "Tijdlijn"
notifications: "Meldingen"
search: "Zoeken"
user-lists: "Lijsten"
game: "Othello spelen"
about: "Over Misskey"
mobile/views/pages/drive.vue:
contextmenu:
upload: "Bestand uploaden"
create-folder: "Map creëren"
mobile/views/pages/home.vue:
home: "Startpagina"
local: "Lokaal"
global: "Algemeen"
mobile/views/pages/widgets.vue:
add-widget: "Toevoegen"
customization-tips: "Aanpassingstips"
mobile/views/pages/widgets/activity.vue:
activity: "Activiteit"
mobile/views/pages/note.vue:
title: "Bericht"
prev: "Vorige notitie"
next: "Volgende notitie"
mobile/views/pages/games/reversi.vue:
reversi: "Othello"
mobile/views/pages/search.vue:
search: "Zoeken"
mobile/views/pages/selectdrive.vue:
select-file: "Kies een bestand"
mobile/views/pages/notifications.vue:
notifications: "Meldingen"
mobile/views/pages/settings.vue:
signed-in-as: "Ingelogd als {}"
mobile/views/pages/user.vue:
follows-you: "Volgt jou"
following: "Volgend"
followers: "Volgers"
notes: "Berichten"
overview: "Overzicht"
timeline: "Tijdlijn"
media: "Media"
mobile/views/pages/user/home.vue:
recent-notes: "Recente notities"
images: "Afbeeldingen"
activity: "Activiteit"
keywords: "Sleutelwoorden"
domains: "Domeinnamen"
frequently-replied-users: "Frequent beantwoord"
followers-you-know: "Volgers die je kent"
last-used-at: "Laatst actief"
mobile/views/pages/user/home.photos.vue:
no-photos: "Geen foto's"
deck:
home: "Startpagina"
local: "Lokaal"
global: "Algemeen"
notifications: "Meldingen"
list: "Lijsten"
rename: "Naam wijzigen"
deck/deck.user-column.vue:
follows-you: "Volgt jou"
posts: "Bericht"
following: "Volgend"
followers: "Volgers"
images: "Afbeeldingen"
activity: "Activiteit"
timeline: "Tijdlijn"
docs:
edit-this-page-on-github: "Heb je een fout ontdekt of wil je bijdragen aan de documentatie? "
edit-this-page-on-github-link: "Bewerk deze pagina op GitHub!"
pages:
pin-this-page: "Vastmaken aan profielpagina"
like: "Leuk"
blocks:
image: "Afbeeldingen"
script:
categories:
list: "Lijsten"
blocks:
_join:
arg1: "Lijsten"
_randomPick:
arg1: "Lijsten"
_dailyRandomPick:
arg1: "Lijsten"
_seedRandomPick:
arg2: "Lijsten"
_pick:
arg1: "Lijsten"
_listLen:
arg1: "Lijsten"
types:
array: "Lijsten"
room:
translate: "Verplaatsen"
furnitures:
moon: "Maan"
bin: "Prullenbak"

View File

@ -1,528 +1 @@
---
meta:
lang: "Norsk Bokmål"
common:
misskey: "En ⭐ av fediverse"
about-title: "En ⭐ av fediverse"
about: "Takk for at du fant Misskey. Misskey er en <b>desentralisert mikroblogging platform</b> født på jorden. Siden den eksisterer sammen med Fediverset (Et univers hvor forskjellige sosiale media-plattformer blir organisert), så blir den gjensidig tilknyttet med andre sosiale media-plattformer. Hvorfor ikke ta en pause fra kjas og mas fra storbyen og hoppe inn i en ny type internett?"
intro:
title: "Hva er Misskey?"
features: "Funksjoner"
rich-contents: "Innlegg"
drive: "Disk"
close: "Lukk"
notification-types:
all: "Alle"
follow: "Følger"
reply: "Svar"
got-it: "Skjønner!"
notification:
file-uploaded: "Filen ble lastet opp!"
message-from: "Melding fra {}:"
reversi-invited: "Invitert til et spill"
reversi-invited-by: "Invitert av {}:"
notified-by: "Invitert av {}:"
reply-from: "Svar fra {}:"
quoted-by: "Sitert av {}:"
time:
unknown: "ukjent"
future: "fremtidig"
just_now: "akkurat nå"
seconds_ago: "{} sekunder siden"
minutes_ago: "{} minutter siden"
hours_ago: "{} t siden"
days_ago: "{} d siden"
weeks_ago: "{} uke(r) siden"
months_ago: "{} måned(er) siden"
years_ago: "{} år siden"
month-and-day: "{day}/{month}"
trash: "Papirkurv"
drive: "Disk"
home: "Hjem"
followers: "Følgere"
favorites: "Merket som favoritt"
permissions:
"write:votes": "Stem"
post-form:
submit: "Innlegg"
reply: "Svar"
error: "Feil"
weekday-short:
sunday: "S"
monday: "M"
tuesday: "T"
wednesday: "O"
thursday: "T"
friday: "F"
saturday: "L"
weekday:
sunday: "Søndag"
monday: "Mandag"
tuesday: "Tirsdag"
wednesday: "Onsdag"
thursday: "Torsdag"
friday: "Fredag"
saturday: "Lørdag"
reactions:
like: "Lik"
love: "Elsk"
laugh: "Le"
hmm: "Hmm…?"
surprise: "Wow"
congrats: "Gratulerer!"
angry: "Sint"
confused: "Forvirret"
rip: "RIP"
pudding: "Pudding"
note-visibility:
public: "Offentlig"
home: "Hjem"
followers: "Følgere"
specified: "Direkte"
_settings:
notification: "Notifikasjon"
password: "Passord"
save: "Lagre"
search: "Søk"
delete: "Slett"
loading: "Laster inn..."
update-available: "En ny versjon av Misskey er nå tilgjengelig ({newer}, nåværende versjon er {current}). Last inn siden igjen for at oppdateringen skal tre i kraft."
my-token-regenerated: "Ditt synbol har blitt generert. Du vil nå bli utlogget."
reversi:
black: "Sort"
white: "Hvit"
total: "Totalt"
widgets:
calendar: "Kalender"
memo: "Notis"
trends: "Populært nå"
version: "Versjon"
notifications: "Notifikasjon"
tips: "Tips"
you: "Du"
auth/views/form.vue:
cancel: "Avbryt"
auth/views/index.vue:
loading: "Laster inn..."
common/views/components/games/reversi/reversi.vue:
matching:
cancel: "Avbryt"
common/views/components/games/reversi/reversi.game.vue:
surrender: "Gi opp"
common/views/components/games/reversi/reversi.index.vue:
invite: "Inviter"
rule: "Slik spiller du"
mode-invite: "Inviter"
game-state:
ended: "Ferdig"
playing: "Pågår"
common/views/components/games/reversi/reversi.room.vue:
random: "Tilfeldig"
black-is: "Sort er {}"
rules: "Regler"
waiting-for-both: "Venter på deg"
cancel: "Avbryt"
ready: "Klar"
cancel-ready: "Avbryt \"Klar\""
common/views/components/connect-failed.vue:
title: "Kunne ikke koble til tjeneren."
description: "Det er enten et problem med internettilknytningen din, eller så har tjeneren blitt tatt ned for vedlikehold. {Prøv igjen} senere."
common/views/components/media-banner.vue:
sensitive: "Sensitivt innhold"
common/views/components/theme.vue:
text-color: "Tekstfarge"
base-theme-dark: "Mørk"
theme-name: "Tema navn"
author: "Forfatter"
desc: "Beskrivelse"
common/views/components/cw-button.vue:
hide: "Skjul"
common/views/components/messaging.vue:
you: "Du"
user: "Bruker"
common/views/components/messaging-room.form.vue:
send: "Send"
common/views/components/messaging-room.message.vue:
is-read: "Lest"
common/views/components/nav.vue:
stats: "Statistikk"
status: "Status"
wiki: "Wiki"
donors: "Donatorer"
repository: "Kodelager"
develop: "Utviklere"
common/views/components/note-menu.vue:
detail: "Detaljer"
favorite: "Merket som favoritt"
pin: "Fest til profilen din"
delete: "Slett"
common/views/components/poll.vue:
vote-count: "{} stemmer"
vote: "Stem"
show-result: "Vis resultater"
voted: "Stemt"
common/views/components/poll-editor.vue:
choice-n: "Valg {}"
day: "S"
common/views/components/signin.vue:
username: "Brukernavn"
password: "Passord"
token: "Token"
or: "Eller"
common/views/components/signup.vue:
username: "Brukernavn"
error: "Nettverksfeil"
password: "Passord"
retype: "Gjenta"
recaptcha: "Captcha"
common/views/components/stream-indicator.vue:
connecting: "Tilkobler"
reconnecting: "Kobler til på nytt"
connected: "Tilkoblet"
common/views/components/notification-settings.vue:
title: "Notifikasjon"
common/views/components/github-setting.vue:
detail: "Detaljer..."
common/views/components/discord-setting.vue:
detail: "Detaljer..."
common/views/components/uploader.vue:
waiting: "Venter"
common/views/components/visibility-chooser.vue:
public: "Offentlig"
home: "Hjem"
followers: "Følgere"
specified: "Direkte"
common/views/components/profile-editor.vue:
name: "Navn"
avatar: "Avatar"
banner: "Banner"
save: "Lagre"
export-targets:
following-list: "Følger"
user-lists: "Lister"
common/views/components/user-list-editor.vue:
users: "Bruker"
common/views/components/user-group-editor.vue:
invite: "Inviter"
common/views/components/user-lists.vue:
user-lists: "Lister"
list-name: "Liste navn"
common/views/components/user-groups.vue:
invites: "Inviter"
common/views/widgets/broadcast.vue:
fetching: "Henter"
next: "Neste"
common/views/widgets/calendar.vue:
year: "År {}"
month: "Måned {}"
day: "Dag {}"
today: "I dag:"
this-month: "Denne måneden:"
this-year: "Dette året:"
common/views/widgets/memo.vue:
title: "Notis"
save: "Lagre"
common/views/pages/follow.vue:
follow: "Følg"
desktop:
banner: "Banner"
avatar: "Avatar"
desktop/views/components/calendar.vue:
prev: "Forrige måned"
next: "Neste måned"
desktop/views/components/choose-file-from-drive-window.vue:
cancel: "Avbryt"
ok: "Ok"
desktop/views/components/choose-folder-from-drive-window.vue:
cancel: "Avbryt"
ok: "Ok"
desktop/views/components/crop-window.vue:
cancel: "Avbryt"
ok: "Ok"
desktop/views/components/drive-window.vue:
used: "brukt"
desktop/views/components/drive.file.vue:
avatar: "Avatar"
banner: "Banner"
nsfw: "NSFW"
contextmenu:
rename: "Endre navn"
copied: "Kopiert"
desktop/views/components/drive.folder.vue:
contextmenu:
rename: "Endre navn"
desktop/views/components/drive.vue:
search: "Søk"
desktop/views/components/media-video.vue:
sensitive: "Innholdet er NSFW"
desktop/views/components/game-window.vue:
game: "Reversi"
desktop/views/components/home.vue:
done: "Fullført"
add: "Legg til"
desktop/views/input-dialog.vue:
cancel: "Avbryt"
ok: "Ok"
desktop/views/components/note-detail.vue:
location: "Lokasjon"
desktop/views/components/note.vue:
reply: "Svar"
detail: "Detaljer"
desktop/views/components/notes.vue:
retry: "Prøv på nytt"
desktop/views/components/post-form-window.vue:
note: "Nytt innlegg"
reply: "Svar"
desktop/views/components/progress-dialog.vue:
waiting: "Venter"
desktop/views/components/renote-form.vue:
cancel: "Avbryt"
desktop/views/components/settings.2fa.vue:
detail: "Detaljer..."
unregister: "Avregistrer"
token: "Token"
submit: "Send"
common/views/components/media-image.vue:
sensitive: "Innholdet er NSFW"
common/views/components/api-settings.vue:
console:
parameter: "Parametere"
send: "Send"
common/views/components/drive-settings.vue:
in-use: "brukt"
stats: "Statistikk"
default-upload-folder-name: "Mappe(r)"
common/views/components/mute-and-block.vue:
save: "Lagre"
desktop/views/components/settings.tags.vue:
add: "Legg til"
save: "Lagre"
desktop/views/components/timeline.vue:
home: "Hjem"
local: "Lokalt"
global: "Globalt"
list: "Lister"
list-name: "Liste navn"
desktop/views/components/ui.header.vue:
adjective: "-san"
desktop/views/components/ui.header.account.vue:
lists: "Lister"
admin: "Admin"
desktop/views/components/ui.header.nav.vue:
game: "Spill"
desktop/views/components/ui.header.notifications.vue:
title: "Notifikasjon"
desktop/views/components/ui.header.post.vue:
post: "Skriv nytt innlegg"
desktop/views/components/ui.header.search.vue:
placeholder: "Søk"
desktop/views/components/user-preview.vue:
notes: "Innlegg"
following: "Følger"
followers: "Følgere"
desktop/views/components/users-list.vue:
all: "Alle"
iknow: "Du kjenner"
desktop/views/components/window.vue:
close: "Lukk"
admin/views/index.vue:
users: "Bruker"
announcements: "Kunngjøringer"
admin/views/dashboard.vue:
notes: "Innlegg"
drive: "Disk"
admin/views/logs.vue:
levels:
info: "Informasjon"
error: "Feil"
admin/views/abuse.vue:
details: "Detaljer"
remove-report: "Slett"
admin/views/instance.vue:
invite: "Inviter"
save: "Lagre"
admin/views/charts.vue:
notes: "Innlegg"
users: "Bruker"
drive: "Disk"
admin/views/drive.vue:
origin:
local: "Lokalt"
delete: "Slett"
admin/views/users.vue:
username: "Brukernavn"
users:
title: "Bruker"
state:
all: "Alle"
origin:
local: "Lokalt"
admin/views/moderators.vue:
logs:
info: "Informasjon"
admin/views/emoji.vue:
add-emoji:
add: "Legg til"
emojis:
remove: "Slett"
admin/views/announcements.vue:
announcements: "Kunngjøringer"
save: "Lagre"
remove: "Slett"
add: "Legg til"
admin/views/federation.vue:
notes: "Innlegg"
users: "Bruker"
followers: "Følgere"
status: "Status"
states:
all: "Alle"
save: "Lagre"
desktop/views/pages/welcome.vue:
announcements: "Kunngjøringer"
info: "Informasjon"
desktop/views/pages/note.vue:
prev: "Forrige innlegg"
next: "Neste innlegg"
desktop/views/pages/selectdrive.vue:
ok: "Ok"
cancel: "Avbryt"
desktop/views/pages/user-list.users.vue:
users: "Bruker"
username: "Brukernavn"
desktop/views/pages/user/user.followers-you-know.vue:
loading: "Laster inn"
desktop/views/pages/user/user.friends.vue:
loading: "Laster inn"
desktop/views/pages/user/user.photos.vue:
title: "Bilder"
loading: "Laster inn"
desktop/views/pages/user/user.header.vue:
posts: "Innlegg"
following: "Følger"
followers: "Følgere"
month: "M"
day: "S"
desktop/views/pages/user/user.timeline.vue:
default: "Innlegg"
with-replies: "Innlegg og svar"
with-media: "Media"
desktop/views/widgets/notifications.vue:
title: "Notifikasjon"
desktop/views/widgets/polls.vue:
refresh: "Oppdater"
desktop/views/widgets/post-form.vue:
title: "Innlegg"
note: "Innlegg"
desktop/views/widgets/trends.vue:
title: "Populært nå"
refresh: "Oppdater"
desktop/views/widgets/users.vue:
refresh: "Oppdater"
no-one: "Ingen"
mobile/views/components/drive.vue:
used: "brukt"
folder-count: "Mappe(r)"
count-separator: ","
file-count: "Fil(er)"
mobile/views/components/drive.file.vue:
nsfw: "NSFW"
mobile/views/components/drive.file-detail.vue:
rename: "Endre navn"
move: "Flytt"
exif: "EXIF"
nsfw: "NSFW"
mobile/views/components/media-video.vue:
sensitive: "Innholdet er NSFW"
common/views/components/follow-button.vue:
follow: "Følger"
mobile/views/components/note.vue:
location: "Lokasjon"
mobile/views/components/note-detail.vue:
reply: "Svar"
location: "Lokasjon"
mobile/views/components/note-preview.vue:
admin: "admin"
bot: "bot"
cat: "katt"
mobile/views/components/note-sub.vue:
admin: "admin"
bot: "bot"
cat: "katt"
mobile/views/components/ui.header.vue:
adjective: "Mr."
mobile/views/components/ui.nav.vue:
notifications: "Notifikasjon"
search: "Søk"
user-lists: "Lister"
game: "Spill"
admin: "Admin"
mobile/views/pages/home.vue:
home: "Hjem"
local: "Lokalt"
global: "Globalt"
mobile/views/pages/widgets.vue:
add-widget: "Legg til"
mobile/views/pages/note.vue:
title: "Innlegg"
prev: "Forrige innlegg"
next: "Neste innlegg"
mobile/views/pages/games/reversi.vue:
reversi: "Reversi"
mobile/views/pages/search.vue:
search: "Søk"
mobile/views/pages/notifications.vue:
notifications: "Notifikasjon"
mobile/views/pages/user.vue:
following: "Følger"
followers: "Følgere"
notes: "Innlegg"
overview: "Oversikt"
media: "Media"
mobile/views/pages/user/home.vue:
recent-notes: "Nylige innlegg"
images: "Bilder"
keywords: "Nøkkelord"
deck:
home: "Hjem"
local: "Lokalt"
global: "Globalt"
notifications: "Notifikasjon"
list: "Lister"
rename: "Endre navn"
deck/deck.user-column.vue:
posts: "Innlegg"
following: "Følger"
followers: "Følgere"
images: "Bilder"
pages:
pin-this-page: "Fest til profilen din"
like: "Lik"
blocks:
image: "Bilder"
script:
categories:
random: "Tilfeldig"
list: "Lister"
blocks:
_join:
arg1: "Lister"
random: "Tilfeldig"
_randomPick:
arg1: "Lister"
_dailyRandomPick:
arg1: "Lister"
_seedRandomPick:
arg2: "Lister"
_pick:
arg1: "Lister"
_listLen:
arg1: "Lister"
types:
array: "Lister"
room:
translate: "Flytt"
save: "Lagre"
furnitures:
moon: "Måne"
bin: "Papirkurv"

File diff suppressed because it is too large Load Diff

View File

@ -1,288 +1 @@
---
meta:
lang: "Português"
common:
misskey: "Uma ⭐ do fediverso"
about-title: "Uma ⭐ do fediverso."
about: "Obrigado por encontrar Misskey. Uma <b>plataforma descentralizada de microblog</b> nascida na Terra. Já que ela existe no Fediverso (um universo onde várias plataformas de mídia social são organizadas), ela é ligada com outras plataformas.Por que você não tira uma folga do agito e confusão da cidade, e mergulha em uma nova internet?"
intro:
title: "O que é Misskey?"
about: "Misskey é um <b>serviço de microblog descentralizado</b>. Personalização sofisticada da interface, variedade de reações a posts, armazenamento de arquivos grátis com gerenciamento integrado e outras funções avançadas estão disponíveis. Um sistema em rede chamado \"Fediverso\" permite que nos comuniquemos com usuários em outras redes sociais. Se você postar algo, por exemplo, seu post não será mandado apenas para o Misskey, mas também para o Mastodon. Apenas imagine que o planeta está enviando ondas de rádio para outros planetas para se comunicar."
features: "Recursos"
rich-contents: "Post"
rich-contents-desc: "Apenas poste suas ideias, temas do momento e qualquer coisa que você queira compartilhar. Você pode querer decorar suas palavras, anexar suas imagens favoritas, enviar arquivos, inclusive vídeos ou criar uma enquete. Essas são as coisas que você pode fazer em Misskey."
reaction: "Reações"
reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません"
application-authorization: "Aplicativos autorizados"
close: "Fechar"
do-not-copy-paste: "Por favor, não digite ou copie o código aqui. A conta pode ser comprometida."
notification-types:
follow: "Seguindo"
got-it: "Entendi!"
customization-tips:
title: "Dicas de personalização"
gotit: "Entendi!"
notification:
file-uploaded: "Arquivo enviado!"
message-from: "Mensagem de {}:"
reversi-invited: "Convidado a jogar"
reversi-invited-by: "Convidado por {}:"
notified-by: "Notificado por {}:"
reply-from: "Resposta de {}:"
quoted-by: "Citado por {}:"
time:
unknown: "Desconhecido"
future: "futuro"
just_now: "agora"
seconds_ago: "{} sec atrás"
minutes_ago: "{} min atrás"
hours_ago: "{} h atrás"
days_ago: "{} d atrás"
weeks_ago: "{} sem atrás"
months_ago: "{} m atrás"
years_ago: "{} ano(s) atrás"
month-and-day: "{day}/{month}"
trash: "Lixo"
timeline: "Linha do tempo"
followers: "Seguidores"
post-form:
enter-username: "Digite o nome de usuário."
username-prompt: "Digite o nome de usuário."
weekday-short:
sunday: "Dom"
monday: "Seg"
tuesday: "Ter"
wednesday: "Qua"
thursday: "Qui"
friday: "Sex"
saturday: "Seb"
weekday:
sunday: "domingo"
monday: "segunda"
tuesday: "terça"
wednesday: "quarta"
thursday: "quinta"
friday: "sexta"
saturday: "sábado"
reactions:
like: "Curtir"
love: "Amei"
laugh: "Riso"
hmm: "Hmm...?"
surprise: "Uau"
congrats: "Parabéns!"
angry: "Raiva"
confused: "Confuso"
rip: "RIP"
pudding: "Pudim"
note-visibility:
followers: "Seguidores"
note-placeholders:
a: "O que está fazendo?"
b: "O que está acontecendo?"
c: "No que está pensando?"
d: "Quer postar algo?"
e: "Escreva aqui"
f: "Esperando você escrever."
_settings:
timeline: "Linha do tempo"
search: "Buscar"
delete: "Apagar"
loading: "Carregando"
update-available-title: "Atualização disponível"
update-available: "Uma nova versão de Misskey está disponível ({newer}). A versão atual é {current}. Recarregue a página para atualizar."
my-token-regenerated: "Seu token foi recriado, portanto você foi deslogado."
enter-username: "Digite o nome de usuário."
reversi:
drawn: "Empatado"
my-turn: "Seu turno"
opponent-turn: "Turno do oponente"
black: "Pretas"
white: "Brancas"
total: "Total"
widgets:
analog-clock: "Relógio analógico"
profile: "Perfil"
calendar: "Calendário"
timemachine: "Calendário (máquina do tempo)"
activity: "Atividade"
rss: "Leitor de RSS"
memo: "Nota adesiva"
trends: "Tendências"
posts-monitor: "Gráfico de publicações"
version: "Versão"
notifications: "Notificações"
users: "Usuário sugeridos"
polls: "Enquetes"
post-form: "Formulário de publicação"
server: "Informações do servidor"
nav: "Navegação"
tips: "Dicas"
hashtags: "Hashtags"
you: "Você"
auth/views/form.vue:
permission-ask: "Este aplicativo precisa das seguintes permissões:"
cancel: "Cancelar"
accept: "Permitir acesso"
auth/views/index.vue:
loading: "Carregando"
already-authorized: "Este aplicativo já foi autorizado"
allowed: "Aplicativos com acesso autorizado"
callback-url: "Voltando ao aplicativo"
please-go-back: "Por favor, volte ao aplicativo."
error: "A sessão não existe."
sign-in: "Por favor, entre."
common/views/components/games/reversi/reversi.index.vue:
invite: "Convidar"
rule: "Como jogar"
mode-invite: "Convidar"
mode-invite-desc: "Convidar um usuário para jogar"
invitations: "Você foi convidado!"
my-games: "Meu jogo"
all-games: "Todos os jogos"
enter-username: "Digite o nome de usuário."
game-state:
ended: "Terminado"
common/views/components/games/reversi/reversi.room.vue:
rules: "Regras"
cancel: "Cancelar"
common/views/components/connect-failed.troubleshooter.vue:
flush: "Limpar o cache"
common/views/components/theme.vue:
desc: "Descrição"
common/views/components/cw-button.vue:
poll: "Enquetes"
common/views/components/messaging.vue:
you: "Você"
common/views/components/note-menu.vue:
delete: "Apagar"
common/views/components/poll-editor.vue:
day: "Dom"
common/views/components/visibility-chooser.vue:
followers: "Seguidores"
common/views/components/profile-editor.vue:
name: "Nome"
export-targets:
following-list: "Seguindo"
common/views/components/user-group-editor.vue:
invite: "Convidar"
common/views/components/user-groups.vue:
invites: "Convidar"
common/views/widgets/posts-monitor.vue:
title: "Gráfico de publicações"
common/views/widgets/memo.vue:
title: "Nota adesiva"
common/views/pages/follow.vue:
follow: "Seguindo"
desktop/views/components/choose-file-from-drive-window.vue:
upload: "Envie arquivos do seu dispositivo"
ok: "OK"
desktop/views/components/choose-folder-from-drive-window.vue:
ok: "OK"
desktop/views/components/crop-window.vue:
ok: "OK"
desktop/views/input-dialog.vue:
ok: "OK"
common/views/components/api-settings.vue:
console:
parameter: "Parâmetros"
desktop/views/components/sub-note-content.vue:
poll: "Enquetes"
desktop/views/components/user-preview.vue:
following: "Seguindo"
followers: "Seguidores"
desktop/views/components/users-list-item.vue:
followed: "Te segue"
admin/views/abuse.vue:
remove-report: "Apagar"
admin/views/instance.vue:
invite: "Convidar"
admin/views/drive.vue:
delete: "Apagar"
admin/views/emoji.vue:
emojis:
remove: "Apagar"
admin/views/announcements.vue:
remove: "Apagar"
admin/views/federation.vue:
followers: "Seguidores"
desktop/views/pages/welcome.vue:
timeline: "Timeline"
powered-by-misskey: "Desenvolvido por <b>Misskey</b>."
desktop/views/pages/drive.vue:
title: "Drive Misskey"
desktop/views/pages/note.vue:
prev: "Nota anterior"
next: "Próxima nota"
desktop/views/pages/selectdrive.vue:
title: "Selecione um arquivo"
ok: "OK"
cancel: "Cancelar"
upload: "Envie arquivos do seu dispositivo"
desktop/views/pages/search.vue:
not-available: "A pesquisa está desligada nas configurações desta instância."
desktop/views/pages/user/user.followers-you-know.vue:
loading: "Carregando"
desktop/views/pages/user/user.friends.vue:
loading: "Carregando"
desktop/views/pages/user/user.photos.vue:
loading: "Carregando"
desktop/views/pages/user/user.header.vue:
following: "Seguindo"
followers: "Seguidores"
month: "Seg"
day: "Dom"
follows-you: "Te segue"
desktop/views/pages/user/user.timeline.vue:
with-media: "Mídia"
desktop/views/widgets/polls.vue:
title: "Enquetes"
common/views/components/follow-button.vue:
follow: "Seguindo"
mobile/views/components/sub-note-content.vue:
poll: "Enquetes"
mobile/views/components/ui.nav.vue:
timeline: "Linha do tempo"
mobile/views/pages/widgets.vue:
customization-tips: "Dicas de personalização"
mobile/views/pages/note.vue:
prev: "Nota anterior"
next: "Próxima nota"
mobile/views/pages/search.vue:
search: "Pesquisar"
mobile/views/pages/user.vue:
follows-you: "Te segue"
following: "Seguindo"
followers: "Seguidores"
notes: "Posts"
timeline: "Linha do tempo"
media: "Mídia"
mobile/views/pages/user/home.vue:
recent-notes: "Notas recentes"
images: "Imagens"
activity: "Atividade"
keywords: "Palavras chave"
domains: "Domínios"
followers-you-know: "Seguidores que você conhece"
last-used-at: "Ativo pela última vez"
mobile/views/pages/user/home.photos.vue:
no-photos: "Sem fotos"
deck/deck.user-column.vue:
follows-you: "Te segue"
following: "Seguindo"
followers: "Seguidores"
images: "Imagens"
timeline: "Linha do tempo"
docs:
edit-this-page-on-github-link: "Edite esta página no GitHub!"
dev/views/index.vue:
manage-apps: "Gerenciar aplicativos"
pages:
like: "Curtir"
blocks:
image: "Imagens"
post: "Formulário de publicação"
room:
furnitures:
moon: "Lua"
bin: "Lixo"

View File

@ -1,171 +1 @@
---
meta:
lang: "Русский язык"
common:
misskey: "Мы — ⭐ fediverse"
about-title: "Мы — ⭐ fediverse"
about: "Спасибо, что нашли Misskey. Misskey — это <b>децентрализованная платформа для микроблоггинга</b> родом с планеты Земля. Поскольку она существует внутри Fediverse (вселенной различных социальных платформ), она связана с другими платформами. Отдохните от шума большого города — и познакомьтесь с новым интернетом."
intro:
title: "Что такое Misskey?"
about: "Misskey - это <b>децентрализованный сервис микроблогинга</b> с открытым исходным кодом. Он имеет такие функции, как: навороченный, полностью настраиваемый пользовательский интерфейс, множество реакций на посты, бесплатное хранилище файлов с интегрированной системой управления и ещё куча передовых фишек. А ещё сетевая система под названием “Fediverse” позволяет нам общаться с пользователями других социальных сетей. Например, если ты что-нибудь запостишь, то твой пост будет отослан не только в Misskey, но ещё и mastodon. Просто представь, что планета посылает микроволны на другую планету для коммуникации."
features: "Особенности"
rich-contents: "Посты"
rich-contents-desc: "Просто выложи свою идею, актуальные темы и всё, что тебе хочется показать миру. Ты можешь декорировать свои слова, прикреплять свои любимые картинки, отправлять файлы с фильмами и создать голосование - это те вещи, которые ты можешь сделать с помощью Misskey!"
reaction: "Реакции"
reaction-desc: "Самый лёгкий способ выразить свои эмоции. Misskey позволяет добавлять различные виды реакций к постам других людей. Эмоциональный опыт из Misskey никогда не появится в других социальных сетях, позволяющих только жать “лайки”."
ui: "Интерфейс"
ui-desc: "Нет такого интерфейса, понравившегося всем. Поэтому у Misskey имеется пользовательский интерфейс, широко настраиваемый под ваши вкусы. Создай себе уникальную домашнюю страницу редактируя, подстраивая оформление ленты и размещая виджеты, которые тоже можно кастомизировать."
drive: "Хранилище файлов"
drive-desc: "Хотите запостить картинку, которую уже отправляли ранее? Хочется сортировать, переименовать и создать папку для ваших выложенных файлов? Тогда Misskey Drive - это лучшее решение для вас. Очень лёгкий способ делиться своими файлами онлайн."
outro: "Попробуйте будущие, уникальные для Misskey функции своими глазами! Если чувствуете, что это не в вашем вкусе, то попробуйте другие инстанции, ведь Misskey - это децентрализованная социальная сеть, так что ты можешь с лёгкостью найти себе товарищей. И наконец, GLHF!"
application-authorization: "Авторизация приложений"
close: "Закрыть"
do-not-copy-paste: "Пожалуйста, не вводите и не вставляйте сюда код. Аккаунту может угрожать опасность."
load-more: "Загрузить больше"
enter-password: "Пожалуйста, введите ваш пароль"
2fa: "Двухфакторная аутентификация"
customize-home: "Настройка домашней страницы"
featured-notes: "Рекомендуемые"
dark-mode: "Тёмная тема"
signin: "Войти"
signup: "Регистрация"
signout: "Выйти"
reload-to-apply-the-setting: "Вам необходимо перезагрузить страницу, чтобы применить настройки. Вы хотите перезагрузить сейчас?"
customization-tips:
title: "Советы по настройке"
gotit: "Понятно!"
notification:
file-uploaded: "Файл отправлен!"
message-from: "Сообщение от {}:"
reversi-invited: "Приглашён в игру"
reversi-invited-by: "Был приглашён {}:"
notified-by: "Был приглашён {}:"
reply-from: "Ответ от {}:"
quoted-by: "Цитировано {}:"
time:
unknown: "неизвестно"
future: "сейчас"
just_now: "сейчас"
seconds_ago: "{} секунд назад"
minutes_ago: "{} минут назад"
hours_ago: "{} часов назад"
days_ago: "{} дней назад"
weeks_ago: "{} недель назад"
months_ago: "{} месяцев назад"
years_ago: "{} лет назад"
month-and-day: "{day}.{month}"
trash: "Мусорное ведро"
drive: "Drive"
pages: "Страницы"
messaging: "Чат"
timeline: "Лента"
followers: "Подписчики"
favorites: "Избранное"
post-form:
reply: "Ответить"
create-poll: "Создать опрос"
weekday-short:
sunday: "Вс"
monday: "Пн"
tuesday: "Вт"
wednesday: "Ср"
thursday: "Чт"
friday: "Пт"
saturday: "Сб"
weekday:
sunday: "Воскресенье"
monday: "Понедельник"
tuesday: "Вторник"
wednesday: "Среда"
thursday: "Четверг"
friday: "Пятница"
saturday: "Суббота"
reactions:
like: "Нравится"
laugh: "Ха-Ха"
rip: "RIP"
do-not-use-in-production: "Эта сборка для разработчиков. Не используйте в продакшне."
error:
title: "Что-то пошло не так :("
retry: "Повторить"
reversi:
drawn: "Ничья"
my-turn: "Ваш ход"
opponent-turn: "Ход оппонента"
turn-of: "Ход {name}"
past-turn-of: "Ход {name}"
won: "{name} победил"
black: "Чёрный"
white: "Белый"
total: "Всего"
this-turn: "Ход {count}"
widgets:
analog-clock: "Аналоговые часы"
profile: "Профиль"
calendar: "Календарь"
timemachine: "Календарь (машина времени)"
activity: "Активность"
rss: "Ридер RSS"
memo: "Заметка"
trends: "Популярное"
photo-stream: "Фотопоток"
slideshow: "Слайдшоу"
version: "Версия"
notifications: "Уведомления"
users: "Рекомендованные пользователи"
polls: "Голосования"
server: "Информация о сервере"
hashtags: "Хэштеги"
dev: "Не удалось создать приложение. Пожалуйста, попробуйте ещё раз."
ai-chan-kawaii: "Ai-chan kawaii!"
auth/views/form.vue:
share-access: "Вы разрешаете <i>{name}</i> получить доступ к вашему аккаунту?"
common/views/components/games/reversi/reversi.index.vue:
game-state:
ended: "Завершено"
playing: "В процессе"
common/views/components/games/reversi/reversi.room.vue:
settings-of-the-game: "Настройки игры"
random: "Случайно"
black-or-white: "Чёрные/Белые"
black-is: "{} ходит чёрными"
rules: "Правила"
settings-of-the-bot: "Настройки бота"
this-game-is-started-soon: "Игра вот-вот начнётся"
waiting-for-other: "Ожидание оппонента"
cancel: "Отмена"
ready: "Готов"
common/views/components/connect-failed.vue:
title: "Невозможно подключиться к серверу"
common/views/components/cw-button.vue:
poll: "Голосования"
common/views/components/poll-editor.vue:
day: "Вс"
common/views/widgets/memo.vue:
title: "Заметка"
desktop/views/components/sub-note-content.vue:
poll: "Голосования"
admin/views/dashboard.vue:
drive: "Хранилище файлов"
admin/views/charts.vue:
drive: "Хранилище файлов"
desktop/views/pages/user/user.header.vue:
month: "Пн"
day: "Вс"
desktop/views/widgets/polls.vue:
title: "Голосования"
mobile/views/components/sub-note-content.vue:
poll: "Голосования"
mobile/views/pages/widgets.vue:
customization-tips: "Советы по настройке"
pages:
like: "Нравится"
script:
categories:
random: "Случайно"
blocks:
random: "Случайно"
room:
furnitures:
moon: "Луна"
bin: "Мусорное ведро"

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +1 @@
---
meta:
lang: "中文(繁体)"
common:
intro:
title: "什麽是 Misskey 呢?"
rich-contents: "發佈"
reaction: "回應"
drive: "雲端硬碟"
close: "關閉"
enter-password: "請輸入密碼"
2fa: "雙重身份驗證"
dark-mode: "夜間模式"
signup: "註冊"
signout: "登出"
notification:
reversi-invited: "您已被邀請加入壹場遊戲"
reversi-invited-by: "來自{}的邀請"
notified-by: "來自{}的邀請"
time:
future: "未來"
just_now: "剛剛"
drive: "雲端硬碟"
weekday:
sunday: "週日"
monday: "週一"
tuesday: "週二"
wednesday: "週三"
thursday: "週四"
friday: "週五"
saturday: "週六"
reactions:
like: "贊"
love: "喜歡"
congrats: "恭喜"
_settings:
password: "密碼"
font-size: "字體大小"
font-size-x-small: "小"
font-size-small: "較小"
deck-column-width-wide: "寬"
timeline: "時間軸"
common/views/components/connect-failed.troubleshooter.vue:
flush: "清除快取"
common/views/components/theme.vue:
light-themes: "淺色主題"
dark-themes: "深色主題"
install-a-theme: "安裝主題"
save-created-theme: "保存主題"
common/views/components/signin.vue:
signin-with-twitter: "用 Twitter 帳號登入"
signin-with-github: "用 GitHub 帳號登入"
signin-with-discord: "用 Discord 帳號登入"
login-failed: "登錄失敗。 請檢查用戶名和密碼。"
common/views/components/signup.vue:
invitation-code: "邀請碼"
username: "用戶名"
available: "可用"
too-long: "請不要超過20個字元"
password: "密碼"
password-placeholder: "建議至少8個字元"
common/views/components/stream-indicator.vue:
connecting: "正在連線"
reconnecting: "正在重新連線"
connected: "已建立連線"
common/views/components/integration-settings.vue:
disconnect: "中斷連線"
common/views/components/github-setting.vue:
reconnect: "重新連線"
disconnect: "中斷連線"
common/views/components/discord-setting.vue:
reconnect: "重新連線"
disconnect: "中斷連線"
common/views/components/language-settings.vue:
recommended: "推薦"
auto: "自動"
specify-language: "指定語言"
common/views/components/profile-editor.vue:
title: "個人資料"
name: "名稱"
birthday: "生日:"
privacy: "隱私"
admin/views/dashboard.vue:
drive: "雲端硬碟"
admin/views/charts.vue:
drive: "雲端硬碟"
pages:
like: "贊"
room:
furnitures:
moon: "月"

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class TalkFederationId1576269851876 implements MigrationInterface {
name = 'TalkFederationId1576269851876'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "messaging_message" ADD "uri" character varying(512)`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "messaging_message" DROP COLUMN "uri"`, undefined);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class ProxyRemoteFiles1576869585998 implements MigrationInterface {
name = 'ProxyRemoteFiles1576869585998'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" ADD "proxyRemoteFiles" boolean NOT NULL DEFAULT false`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyRemoteFiles"`, undefined);
}
}

View File

@ -0,0 +1,34 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v121579267006611 implements MigrationInterface {
name = 'v121579267006611'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "announcement" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "text" character varying(8192) NOT NULL, "title" character varying(256) NOT NULL, "imageUrl" character varying(1024), CONSTRAINT "PK_e0ef0550174fd1099a308fd18a0" PRIMARY KEY ("id"))`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_118ec703e596086fc4515acb39" ON "announcement" ("createdAt") `, undefined);
await queryRunner.query(`CREATE TABLE "announcement_read" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "announcementId" character varying(32) NOT NULL, CONSTRAINT "PK_4b90ad1f42681d97b2683890c5e" PRIMARY KEY ("id"))`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_8288151386172b8109f7239ab2" ON "announcement_read" ("userId") `, undefined);
await queryRunner.query(`CREATE INDEX "IDX_603a7b1e7aa0533c6c88e9bfaf" ON "announcement_read" ("announcementId") `, undefined);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_924fa71815cfa3941d003702a0" ON "announcement_read" ("userId", "announcementId") `, undefined);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isVerified"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "announcements"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableEmojiReaction"`, undefined);
await queryRunner.query(`ALTER TABLE "announcement_read" ADD CONSTRAINT "FK_8288151386172b8109f7239ab28" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "announcement_read" ADD CONSTRAINT "FK_603a7b1e7aa0533c6c88e9bfafe" FOREIGN KEY ("announcementId") REFERENCES "announcement"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "announcement_read" DROP CONSTRAINT "FK_603a7b1e7aa0533c6c88e9bfafe"`, undefined);
await queryRunner.query(`ALTER TABLE "announcement_read" DROP CONSTRAINT "FK_8288151386172b8109f7239ab28"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableEmojiReaction" boolean NOT NULL DEFAULT true`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ADD "announcements" jsonb NOT NULL DEFAULT '[]'`, undefined);
await queryRunner.query(`ALTER TABLE "user" ADD "isVerified" boolean NOT NULL DEFAULT false`, undefined);
await queryRunner.query(`DROP INDEX "IDX_924fa71815cfa3941d003702a0"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_603a7b1e7aa0533c6c88e9bfaf"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_8288151386172b8109f7239ab2"`, undefined);
await queryRunner.query(`DROP TABLE "announcement_read"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_118ec703e596086fc4515acb39"`, undefined);
await queryRunner.query(`DROP TABLE "announcement"`, undefined);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1221579270193251 implements MigrationInterface {
name = 'v1221579270193251'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "announcement_read" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "announcement_read" DROP COLUMN "createdAt"`, undefined);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1231579282808087 implements MigrationInterface {
name = 'v1231579282808087'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "announcement" ADD "updatedAt" TIMESTAMP WITH TIME ZONE`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "updatedAt"`, undefined);
}
}

View File

@ -0,0 +1,16 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1241579544426412 implements MigrationInterface {
name = 'v1241579544426412'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "notification" ADD "followRequestId" character varying(32)`, undefined);
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_bd7fab507621e635b32cd31892c" FOREIGN KEY ("followRequestId") REFERENCES "follow_request"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_bd7fab507621e635b32cd31892c"`, undefined);
await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "followRequestId"`, undefined);
}
}

View File

@ -0,0 +1,54 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1251579977526288 implements MigrationInterface {
name = 'v1251579977526288'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "clip" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "name" character varying(128) NOT NULL, "isPublic" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_f0685dac8d4dd056d7255670b75" PRIMARY KEY ("id"))`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_2b5ec6c574d6802c94c80313fb" ON "clip" ("userId") `, undefined);
await queryRunner.query(`CREATE TABLE "clip_note" ("id" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "clipId" character varying(32) NOT NULL, CONSTRAINT "PK_e94cda2f40a99b57e032a1a738b" PRIMARY KEY ("id"))`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_a012eaf5c87c65da1deb5fdbfa" ON "clip_note" ("noteId") `, undefined);
await queryRunner.query(`CREATE INDEX "IDX_ebe99317bbbe9968a0c6f579ad" ON "clip_note" ("clipId") `, undefined);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_6fc0ec357d55a18646262fdfff" ON "clip_note" ("noteId", "clipId") `, undefined);
await queryRunner.query(`CREATE TYPE "antenna_src_enum" AS ENUM('home', 'all', 'list')`, undefined);
await queryRunner.query(`CREATE TABLE "antenna" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "name" character varying(128) NOT NULL, "src" "antenna_src_enum" NOT NULL, "userListId" character varying(32), "keywords" jsonb NOT NULL DEFAULT '[]', "withFile" boolean NOT NULL, "expression" character varying(2048), "notify" boolean NOT NULL, "hasNewNote" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_c170b99775e1dccca947c9f2d5f" PRIMARY KEY ("id"))`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_6446c571a0e8d0f05f01c78909" ON "antenna" ("userId") `, undefined);
await queryRunner.query(`CREATE TABLE "antenna_note" ("id" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "antennaId" character varying(32) NOT NULL, CONSTRAINT "PK_fb28d94d0989a3872df19fd6ef8" PRIMARY KEY ("id"))`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_bd0397be22147e17210940e125" ON "antenna_note" ("noteId") `, undefined);
await queryRunner.query(`CREATE INDEX "IDX_0d775946662d2575dfd2068a5f" ON "antenna_note" ("antennaId") `, undefined);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_335a0bf3f904406f9ef3dd51c2" ON "antenna_note" ("noteId", "antennaId") `, undefined);
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "geo"`, undefined);
await queryRunner.query(`ALTER TABLE "clip" ADD CONSTRAINT "FK_2b5ec6c574d6802c94c80313fb2" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "clip_note" ADD CONSTRAINT "FK_a012eaf5c87c65da1deb5fdbfa3" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "clip_note" ADD CONSTRAINT "FK_ebe99317bbbe9968a0c6f579adf" FOREIGN KEY ("clipId") REFERENCES "clip"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" ADD CONSTRAINT "FK_6446c571a0e8d0f05f01c789096" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" ADD CONSTRAINT "FK_709d7d32053d0dd7620f678eeb9" FOREIGN KEY ("userListId") REFERENCES "user_list"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "antenna_note" ADD CONSTRAINT "FK_bd0397be22147e17210940e125b" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
await queryRunner.query(`ALTER TABLE "antenna_note" ADD CONSTRAINT "FK_0d775946662d2575dfd2068a5f5" FOREIGN KEY ("antennaId") REFERENCES "antenna"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "antenna_note" DROP CONSTRAINT "FK_0d775946662d2575dfd2068a5f5"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna_note" DROP CONSTRAINT "FK_bd0397be22147e17210940e125b"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" DROP CONSTRAINT "FK_709d7d32053d0dd7620f678eeb9"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" DROP CONSTRAINT "FK_6446c571a0e8d0f05f01c789096"`, undefined);
await queryRunner.query(`ALTER TABLE "clip_note" DROP CONSTRAINT "FK_ebe99317bbbe9968a0c6f579adf"`, undefined);
await queryRunner.query(`ALTER TABLE "clip_note" DROP CONSTRAINT "FK_a012eaf5c87c65da1deb5fdbfa3"`, undefined);
await queryRunner.query(`ALTER TABLE "clip" DROP CONSTRAINT "FK_2b5ec6c574d6802c94c80313fb2"`, undefined);
await queryRunner.query(`ALTER TABLE "note" ADD "geo" jsonb`, undefined);
await queryRunner.query(`DROP INDEX "IDX_335a0bf3f904406f9ef3dd51c2"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_0d775946662d2575dfd2068a5f"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_bd0397be22147e17210940e125"`, undefined);
await queryRunner.query(`DROP TABLE "antenna_note"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_6446c571a0e8d0f05f01c78909"`, undefined);
await queryRunner.query(`DROP TABLE "antenna"`, undefined);
await queryRunner.query(`DROP TYPE "antenna_src_enum"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_6fc0ec357d55a18646262fdfff"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_ebe99317bbbe9968a0c6f579ad"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_a012eaf5c87c65da1deb5fdbfa"`, undefined);
await queryRunner.query(`DROP TABLE "clip_note"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_2b5ec6c574d6802c94c80313fb"`, undefined);
await queryRunner.query(`DROP TABLE "clip"`, undefined);
}
}

View File

@ -0,0 +1,18 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1261579993013959 implements MigrationInterface {
name = 'v1261579993013959'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "hasNewNote"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna_note" ADD "read" boolean NOT NULL DEFAULT false`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_9937ea48d7ae97ffb4f3f063a4" ON "antenna_note" ("read") `, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_9937ea48d7ae97ffb4f3f063a4"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna_note" DROP COLUMN "read"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" ADD "hasNewNote" boolean NOT NULL DEFAULT false`, undefined);
}
}

View File

@ -0,0 +1,24 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1271580069531114 implements MigrationInterface {
name = 'v1271580069531114'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "antenna" ADD "users" character varying(1024) array NOT NULL DEFAULT '{}'::varchar[]`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" ADD "caseSensitive" boolean NOT NULL DEFAULT false`, 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')`, 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);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TYPE "antenna_src_enum_old" AS ENUM('home', 'all', '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 "caseSensitive"`, undefined);
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "users"`, undefined);
}
}

View File

@ -0,0 +1,16 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1281580148575182 implements MigrationInterface {
name = 'v1281580148575182'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_ec5c201576192ba8904c345c5cc"`, undefined);
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "appId"`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "note" ADD "appId" character varying(32)`, undefined);
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_ec5c201576192ba8904c345c5cc" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE SET NULL ON UPDATE NO ACTION`, undefined);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v1291580154400017 implements MigrationInterface {
name = 'v1291580154400017'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "antenna" ADD "withReplies" boolean NOT NULL DEFAULT false`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "withReplies"`, undefined);
}
}

View File

@ -0,0 +1,19 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v12101580276619901 implements MigrationInterface {
name = 'v12101580276619901'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`TRUNCATE TABLE "notification"`, undefined);
await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "type"`, undefined);
await queryRunner.query(`CREATE TYPE "notification_type_enum" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest', 'followRequestAccepted')`, undefined);
await queryRunner.query(`ALTER TABLE "notification" ADD "type" "notification_type_enum" NOT NULL`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "type"`, undefined);
await queryRunner.query(`DROP TYPE "notification_type_enum"`, undefined);
await queryRunner.query(`ALTER TABLE "notification" ADD "type" character varying(32) NOT NULL`, undefined);
}
}

View File

@ -0,0 +1,18 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v12111580331224276 implements MigrationInterface {
name = 'v12111580331224276'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isMarkedAsClosed"`, undefined);
await queryRunner.query(`ALTER TABLE "instance" ADD "isSuspended" boolean NOT NULL DEFAULT false`, undefined);
await queryRunner.query(`CREATE INDEX "IDX_34500da2e38ac393f7bb6b299c" ON "instance" ("isSuspended") `, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_34500da2e38ac393f7bb6b299c"`, undefined);
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "isSuspended"`, undefined);
await queryRunner.query(`ALTER TABLE "instance" ADD "isMarkedAsClosed" boolean NOT NULL DEFAULT false`, undefined);
}
}

View File

@ -0,0 +1,46 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v12121580508795118 implements MigrationInterface {
name = 'v12121580508795118'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twitter"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twitterAccessToken"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twitterAccessTokenSecret"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twitterUserId"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twitterScreenName"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "github"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "githubAccessToken"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "githubId"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "githubLogin"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discord"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordAccessToken"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordRefreshToken"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordExpiresDate"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordId"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordUsername"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordDiscriminator"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "integrations" jsonb NOT NULL DEFAULT '{}'`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "integrations"`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discordDiscriminator" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discordUsername" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discordId" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discordExpiresDate" character varying(64)`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discordRefreshToken" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discordAccessToken" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "discord" boolean NOT NULL DEFAULT false`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "githubLogin" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "githubId" character varying(64)`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "githubAccessToken" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "github" boolean NOT NULL DEFAULT false`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "twitterScreenName" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "twitterUserId" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "twitterAccessTokenSecret" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "twitterAccessToken" character varying(64) DEFAULT NULL`, undefined);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "twitter" boolean NOT NULL DEFAULT false`, undefined);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v12131580543501339 implements MigrationInterface {
name = 'v12131580543501339'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE INDEX "IDX_NOTE_TAGS" ON "note" USING gin ("tags")`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_NOTE_TAGS"`, undefined);
}
}

View File

@ -0,0 +1,20 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class v12141580864313253 implements MigrationInterface {
name = 'v12141580864313253'
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "proxyAccount" TO "proxyAccountId"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyAccountId"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ADD "proxyAccountId" character varying(32)`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ADD CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad" FOREIGN KEY ("proxyAccountId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`, undefined);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" DROP CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyAccountId"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ADD "proxyAccountId" character varying(128)`, undefined);
await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "proxyAccountId" TO "proxyAccount"`, undefined);
}
}

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "11.35.1",
"codename": "daybreak",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.0.0",
"codename": "indigo",
"repository": {
"type": "git",
"url": "https://github.com/syuilo/misskey.git"
@ -22,60 +22,56 @@
"clean": "gulp clean",
"cleanall": "gulp cleanall",
"lint": "gulp lint",
"test": "gulp test",
"test": "cross-env TS_NODE_FILES=true gulp test",
"format": "gulp format"
},
"resolutions": {
"gulp-cssnano/cssnano/postcss-svgo/svgo/js-yaml": "^3.13.1",
"https-proxy-agent": "^3.0.0",
"lodash": "^4.17.13"
},
"dependencies": {
"@elastic/elasticsearch": "7.4.0",
"@fortawesome/fontawesome-svg-core": "1.2.25",
"@fortawesome/free-brands-svg-icons": "5.11.2",
"@fortawesome/free-regular-svg-icons": "5.11.2",
"@fortawesome/free-solid-svg-icons": "5.11.2",
"@fortawesome/vue-fontawesome": "0.1.7",
"@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",
"@fortawesome/vue-fontawesome": "0.1.9",
"@koa/cors": "3.0.0",
"@koa/multer": "2.0.0",
"@koa/router": "8.0.2",
"@koa/multer": "2.0.2",
"@koa/router": "8.0.6",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.10.3",
"@types/cbor": "2.0.0",
"@types/bull": "3.12.0",
"@types/cbor": "5.0.0",
"@types/dateformat": "3.0.1",
"@types/deep-equal": "1.0.1",
"@types/double-ended-queue": "2.1.1",
"@types/gulp": "4.0.6",
"@types/gulp-mocha": "0.0.32",
"@types/gulp-rename": "0.0.33",
"@types/gulp-replace": "0.0.31",
"@types/gulp-uglify": "3.0.6",
"@types/gulp-util": "3.0.34",
"@types/is-url": "1.2.28",
"@types/js-yaml": "3.12.1",
"@types/js-yaml": "3.12.2",
"@types/jsdom": "12.2.4",
"@types/katex": "0.10.2",
"@types/koa": "2.0.50",
"@types/koa-bodyparser": "5.0.2",
"@types/katex": "0.11.0",
"@types/koa": "2.11.0",
"@types/koa-bodyparser": "4.3.0",
"@types/koa-compress": "2.0.9",
"@types/koa-cors": "0.0.0",
"@types/koa-favicon": "2.0.19",
"@types/koa-logger": "3.1.1",
"@types/koa-mount": "4.0.0",
"@types/koa-send": "4.1.2",
"@types/koa-views": "2.0.3",
"@types/koa__cors": "2.2.3",
"@types/koa__multer": "2.0.0",
"@types/koa__router": "8.0.0",
"@types/lolex": "3.1.1",
"@types/mocha": "5.2.7",
"@types/node": "12.7.12",
"@types/nodemailer": "6.2.1",
"@types/koa-views": "2.0.4",
"@types/koa__cors": "3.0.1",
"@types/koa__multer": "2.0.1",
"@types/koa__router": "8.0.2",
"@types/lolex": "5.1.0",
"@types/mocha": "7.0.1",
"@types/node": "13.7.0",
"@types/nodemailer": "6.4.0",
"@types/nprogress": "0.2.0",
"@types/oauth": "0.9.1",
"@types/parse5": "5.0.2",
"@types/parsimmon": "1.10.0",
"@types/parsimmon": "1.10.1",
"@types/portscanner": "2.1.0",
"@types/pug": "2.0.4",
"@types/qrcode": "1.3.4",
@ -83,80 +79,78 @@
"@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.14",
"@types/rename": "1.0.1",
"@types/request": "2.48.3",
"@types/request": "2.48.4",
"@types/request-promise-native": "1.0.17",
"@types/request-stats": "3.0.0",
"@types/rimraf": "2.0.2",
"@types/rimraf": "2.0.3",
"@types/seedrandom": "2.4.28",
"@types/sharp": "0.22.3",
"@types/sharp": "0.24.0",
"@types/showdown": "1.9.3",
"@types/speakeasy": "2.0.5",
"@types/systeminformation": "3.23.1",
"@types/systeminformation": "3.54.1",
"@types/tinycolor2": "1.4.2",
"@types/tmp": "0.1.0",
"@types/uuid": "3.4.5",
"@types/uuid": "3.4.7",
"@types/web-push": "3.3.0",
"@types/webpack": "4.39.3",
"@types/webpack": "4.41.3",
"@types/webpack-stream": "3.2.10",
"@types/websocket": "0.0.40",
"@types/ws": "6.0.3",
"@typescript-eslint/parser": "2.3.3",
"@types/websocket": "1.0.0",
"@types/ws": "7.2.1",
"@typescript-eslint/parser": "2.18.0",
"agentkeepalive": "4.1.0",
"animejs": "3.1.0",
"apexcharts": "3.10.1",
"apexcharts": "3.15.3",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
"aws-sdk": "2.548.0",
"aws-sdk": "2.610.0",
"bcryptjs": "2.4.3",
"bootstrap": "4.3.1",
"bootstrap-vue": "2.0.4",
"bull": "3.11.0",
"cafy": "15.1.1",
"bull": "3.12.1",
"cafy": "15.2.1",
"cbor": "5.0.1",
"chai": "4.2.0",
"chalk": "2.4.2",
"cli-highlight": "2.1.1",
"commander": "3.0.2",
"chalk": "3.0.0",
"chart.js": "2.9.3",
"cli-highlight": "2.1.4",
"commander": "4.1.0",
"content-disposition": "0.5.3",
"crc-32": "1.2.0",
"css-loader": "3.2.0",
"css-loader": "3.4.2",
"cssnano": "4.1.10",
"dateformat": "3.0.3",
"deep-equal": "1.1.0",
"diskusage": "1.1.3",
"double-ended-queue": "2.1.0-0",
"eslint": "6.5.1",
"eslint-plugin-vue": "5.2.3",
"eslint": "6.8.0",
"eslint-plugin-vue": "6.1.2",
"eventemitter3": "4.0.0",
"feed": "4.0.0",
"file-type": "12.3.0",
"feed": "4.1.0",
"fibers": "4.0.2",
"file-type": "13.1.2",
"fluent-ffmpeg": "2.1.2",
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-clean-css": "4.2.0",
"gulp-dart-sass": "0.9.1",
"gulp-mocha": "7.0.2",
"gulp-rename": "1.4.0",
"gulp-rename": "2.0.0",
"gulp-replace": "1.0.0",
"gulp-sourcemaps": "2.6.5",
"gulp-stylus": "2.7.0",
"gulp-terser": "1.2.0",
"gulp-tslint": "8.1.4",
"gulp-typescript": "5.0.1",
"gulp-uglify": "3.0.2",
"gulp-util": "3.0.8",
"hard-source-webpack-plugin": "0.13.1",
"html-minifier": "4.0.0",
"http-signature": "1.2.0",
"https-proxy-agent": "3.0.0",
"http-signature": "1.3.1",
"https-proxy-agent": "4.0.0",
"insert-text-at-cursor": "0.3.0",
"is-root": "2.1.0",
"is-svg": "4.2.0",
"is-svg": "4.2.1",
"js-yaml": "3.13.1",
"jsdom": "15.1.1",
"jsdom": "16.0.1",
"json5": "2.1.1",
"json5-loader": "3.0.0",
"jsrsasign": "8.0.12",
"katex": "0.11.1",
"koa": "2.10.0",
"koa": "2.11.0",
"koa-bodyparser": "4.2.1",
"koa-compress": "3.0.0",
"koa-favicon": "2.0.1",
@ -168,104 +162,105 @@
"koa-views": "6.2.1",
"langmap": "0.0.16",
"loader-utils": "1.2.3",
"lolex": "4.2.0",
"lolex": "5.1.2",
"lookup-dns-cache": "2.1.0",
"mocha": "6.2.1",
"mocha": "7.0.1",
"moji": "0.5.1",
"ms": "2.1.2",
"multer": "1.4.2",
"nested-property": "1.0.1",
"nested-property": "1.0.4",
"node-fetch": "2.6.0",
"nodemailer": "6.3.1",
"nodemailer": "6.4.2",
"nprogress": "0.2.0",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14",
"parse5": "5.1.0",
"parse5": "5.1.1",
"parsimmon": "1.13.0",
"pg": "7.12.1",
"pg": "7.18.1",
"portal-vue": "2.1.7",
"portscanner": "2.2.0",
"postcss-loader": "3.0.0",
"prismjs": "1.17.1",
"progress-bar-webpack-plugin": "1.12.1",
"prismjs": "1.19.0",
"probe-image-size": "5.0.0",
"progress-bar-webpack-plugin": "2.1.0",
"promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
"pug": "2.0.4",
"punycode": "2.1.1",
"pureimage": "0.1.6",
"qrcode": "1.4.2",
"qrcode": "1.4.4",
"random-seed": "0.3.0",
"randomcolor": "0.5.4",
"ratelimiter": "3.3.1",
"ratelimiter": "3.4.0",
"recaptcha-promise": "0.1.3",
"reconnecting-websocket": "4.2.0",
"reconnecting-websocket": "4.3.0",
"redis": "2.8.0",
"redis-lock": "0.1.4",
"reflect-metadata": "0.1.13",
"rename": "1.0.4",
"request": "2.88.0",
"request-promise-native": "1.0.7",
"request-promise-native": "1.0.8",
"request-stats": "3.0.0",
"require-all": "3.0.0",
"rimraf": "3.0.0",
"rimraf": "3.0.1",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sass": "1.25.0",
"sass-loader": "8.0.2",
"seedrandom": "3.0.5",
"sharp": "0.23.1",
"showdown": "1.9.0",
"sharp": "0.24.0",
"showdown": "1.9.1",
"showdown-highlightjs-extension": "0.1.2",
"speakeasy": "2.0.0",
"stringz": "2.0.0",
"style-loader": "1.0.0",
"stylus": "0.54.7",
"stylus-loader": "3.0.2",
"style-loader": "1.1.3",
"summaly": "2.3.1",
"syslog-pro": "1.0.0",
"systeminformation": "4.14.11",
"systeminformation": "4.21.1",
"syuilo-password-strength": "0.0.1",
"terser-webpack-plugin": "2.1.3",
"terser-webpack-plugin": "2.3.4",
"textarea-caret": "3.1.0",
"three": "0.109.0",
"three": "0.113.2",
"tinycolor2": "1.4.1",
"tmp": "0.1.0",
"ts-loader": "6.2.0",
"ts-node": "8.4.1",
"tslint": "5.20.0",
"ts-loader": "6.2.1",
"ts-node": "8.6.2",
"tslint": "6.0.0",
"tslint-sonarts": "1.9.0",
"typeorm": "0.2.19",
"typescript": "3.6.4",
"uglify-es": "3.3.9",
"typeorm": "0.2.22",
"typescript": "3.7.5",
"ulid": "2.3.0",
"url-loader": "2.2.0",
"uuid": "3.3.3",
"url-loader": "3.0.0",
"uuid": "3.4.0",
"v-animate-css": "0.0.3",
"v-debounce": "0.1.2",
"vue": "2.6.10",
"vue": "2.6.11",
"vue-color": "2.7.0",
"vue-content-loading": "1.6.0",
"vue-cropperjs": "4.0.0",
"vue-i18n": "8.14.1",
"vue-js-modal": "1.3.31",
"vue-json-pretty": "1.6.2",
"vue-loader": "15.7.1",
"vue-cropperjs": "4.0.1",
"vue-i18n": "8.15.3",
"vue-json-pretty": "1.6.3",
"vue-loader": "15.8.3",
"vue-marquee-text-component": "1.1.1",
"vue-meta": "2.3.2",
"vue-prism-component": "1.1.1",
"vue-router": "3.1.3",
"vue-router": "3.1.5",
"vue-sequential-entrance": "1.1.3",
"vue-style-loader": "4.1.2",
"vue-svg-inline-loader": "1.3.3",
"vue-template-compiler": "2.6.10",
"vue-svg-inline-loader": "1.4.5",
"vue-template-compiler": "2.6.11",
"vuedraggable": "2.23.2",
"vuewordcloud": "18.7.11",
"vuex": "3.1.1",
"vuex-persistedstate": "2.5.4",
"web-push": "3.4.0",
"webpack": "4.41.1",
"webpack-cli": "3.3.9",
"websocket": "1.0.30",
"ws": "7.1.2",
"vuex": "3.1.2",
"vuex-persistedstate": "2.7.0",
"web-push": "3.4.3",
"webpack": "4.41.5",
"webpack-cli": "3.3.10",
"websocket": "1.0.31",
"ws": "7.2.1",
"xev": "2.0.1"
},
"devDependencies": {
"@types/fluent-ffmpeg": "2.1.10"
"@types/fluent-ffmpeg": "2.1.12",
"cross-env": "6.0.3"
}
}

View File

@ -1,3 +0,0 @@
declare module '*/const.json' {
const copyright: string;
}

27
src/@types/probe-image-size.d.ts vendored Normal file
View File

@ -0,0 +1,27 @@
declare module 'probe-image-size' {
import { ReadStream } from 'fs';
type ProbeOptions = {
retries: 1;
timeout: 30000;
};
type ProbeResult = {
width: number;
height: number;
length?: number;
type: string;
mime: string;
wUnits: 'in' | 'mm' | 'cm' | 'pt' | 'pc' | 'px' | 'em' | 'ex';
hUnits: 'in' | 'mm' | 'cm' | 'pt' | 'pc' | 'px' | 'em' | 'ex';
url?: string;
};
function probeImageSize(src: string | ReadStream, options?: ProbeOptions): Promise<ProbeResult>;
function probeImageSize(src: string | ReadStream, callback: (err: Error | null, result?: ProbeResult) => void): void;
function probeImageSize(src: string | ReadStream, options: ProbeOptions, callback: (err: Error | null, result?: ProbeResult) => void): void;
namespace probeImageSize {} // Hack
export = probeImageSize;
}

View File

@ -1,5 +1,5 @@
import * as cluster from 'cluster';
import chalk from 'chalk';
import * as chalk from 'chalk';
import Xev from 'xev';
import Logger from '../services/logger';

View File

@ -1,6 +1,6 @@
import * as os from 'os';
import * as cluster from 'cluster';
import chalk from 'chalk';
import * as chalk from 'chalk';
import * as portscanner from 'portscanner';
import * as isRoot from 'is-root';
@ -11,14 +11,15 @@ import { lessThan } from '../prelude/array';
import { program } from '../argv';
import { showMachineInfo } from '../misc/show-machine-info';
import { initDb } from '../db/postgre';
import * as meta from '../meta.json';
const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta', false);
function greet(config: Config) {
function greet() {
if (!program.quiet) {
//#region Misskey logo
const v = `v${config.version}`;
const v = `v${meta.version}`;
console.log(' _____ _ _ ');
console.log(' | |_|___ ___| |_ ___ _ _ ');
console.log(' | | | | |_ -|_ -| \'_| -_| | |');
@ -26,7 +27,7 @@ function greet(config: Config) {
console.log(' ' + chalk.gray(v) + (' |___|\n'.substr(v.length)));
//#endregion
console.log(' Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, @acid-chicken, and @rinsuki.');
console.log(' Misskey is an open-source decentralized microblogging platform.');
console.log(chalk.keyword('orange')(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo'));
console.log('');
@ -34,7 +35,7 @@ function greet(config: Config) {
}
bootLogger.info('Welcome to Misskey!');
bootLogger.info(`Misskey v${config.version}`, null, true);
bootLogger.info(`Misskey v${meta.version}`, null, true);
}
/**
@ -44,11 +45,11 @@ export async function masterMain() {
let config!: Config;
try {
greet();
// initialize app
config = await init();
greet(config);
if (config.port == null || Number.isNaN(config.port)) {
bootLogger.error('The port is not configured. Please configure port.', null, true);
process.exit(1);
@ -76,7 +77,6 @@ export async function masterMain() {
if (!program.noDaemons) {
require('../daemons/server-stats').default();
require('../daemons/notes-stats').default();
require('../daemons/queue-stats').default();
require('../daemons/janitor').default();
}

1110
src/client/app.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,150 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46667 135.46667"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="header-icon.dark.svg"
inkscape:export-filename="C:\Users\syuilo\projects\misskey\assets\favicon\32.png"
inkscape:export-xdpi="6"
inkscape:export-ydpi="6">
<defs
id="defs2">
<inkscape:path-effect
effect="simplify"
id="path-effect5115"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
<inkscape:path-effect
effect="simplify"
id="path-effect5111"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
<inkscape:path-effect
effect="simplify"
id="path-effect5104"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="114.309"
inkscape:cy="251.50613"
inkscape:document-units="px"
inkscape:current-layer="g4502"
showgrid="true"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:snap-smooth-nodes="true"
inkscape:snap-center="true"
inkscape:snap-page="true"
inkscape:window-width="1920"
inkscape:window-height="1027"
inkscape:window-x="-8"
inkscape:window-y="1072"
inkscape:window-maximized="1"
inkscape:snap-object-midpoints="true"
inkscape:snap-midpoints="true"
inkscape:object-paths="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
objecttolerance="1"
guidetolerance="1"
inkscape:snap-nodes="false"
inkscape:snap-others="false">
<inkscape:grid
type="xygrid"
id="grid4504"
spacingx="4.2333334"
spacingy="4.2333334"
empcolor="#ff3fff"
empopacity="0.25098039"
empspacing="4" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="レイヤー 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-30.809093,-111.78601)">
<g
id="g4502"
transform="matrix(1.096096,0,0,1.096096,-2.960633,-44.023579)">
<g
style="fill-opacity:1"
transform="translate(-1.3333333e-6,-1.3439941e-6)"
id="g5125">
<g
transform="matrix(0.91391326,0,0,0.91391326,7.9719907,17.595761)"
id="text4489"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.03404236px;line-height:476.69509888px;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';letter-spacing:0px;word-spacing:0px;fill-opacity:1;stroke:none;stroke-width:0.28950602px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
aria-label="Mi">
<path
sodipodi:nodetypes="zccssscssccscczzzccsccsscscsccz"
inkscape:connector-curvature="0"
id="path5210"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill-opacity:1;stroke-width:0.28950602px"
d="m 75.196381,231.17126 c -5.855419,0.0202 -10.885068,-3.50766 -13.2572,-7.61584 -1.266603,-1.79454 -3.772419,-2.43291 -3.807919,0 v 11.2332 c 0,4.51309 -1.645397,8.41504 -4.936191,11.70583 -3.196772,3.19677 -7.098714,4.79516 -11.705826,4.79516 -4.513089,0 -8.415031,-1.59839 -11.705825,-4.79516 -3.196772,-3.29079 -4.795158,-7.19274 -4.795158,-11.70583 v -61.7729 c 0,-3.47884 0.987238,-6.6286 2.961715,-9.44928 2.068499,-2.91471 4.701135,-4.9362 7.897906,-6.06447 1.786431,-0.65816 3.666885,-0.98724 5.641362,-0.98724 5.077225,0 9.308247,1.97448 12.693064,5.92343 1.786431,1.97448 2.820681,3.00873 3.102749,3.10275 0,0 13.408119,16.21319 13.78421,16.49526 0.376091,0.28206 1.480789,2.43848 4.127113,2.43848 2.646324,0 3.89218,-2.15642 4.26827,-2.43848 0.376091,-0.28207 13.784088,-16.49526 13.784088,-16.49526 0.09402,0.094 1.081261,-0.94022 2.961715,-3.10275 3.478837,-3.94895 7.756866,-5.92343 12.834096,-5.92343 1.88045,0 3.76091,0.32908 5.64136,0.98724 3.19677,1.12827 5.7824,3.14976 7.75688,6.06447 2.06849,2.82068 3.10274,5.97044 3.10274,9.44928 v 61.7729 c 0,4.51309 -1.6454,8.41504 -4.93619,11.70583 -3.19677,3.19677 -7.09871,4.79516 -11.70582,4.79516 -4.51309,0 -8.41504,-1.59839 -11.705828,-4.79516 -3.196772,-3.29079 -4.795158,-7.19274 -4.795158,-11.70583 v -11.2332 c -0.277898,-3.06563 -2.987588,-1.13379 -3.948953,0 -2.538613,4.70114 -7.401781,7.59567 -13.2572,7.61584 z" />
<path
inkscape:connector-curvature="0"
id="path5212"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill-opacity:1;stroke-width:0.28950602px"
d="m 145.83461,185.00361 q -5.92343,0 -10.15445,-4.08999 -4.08999,-4.23102 -4.08999,-10.15445 0,-5.92343 4.08999,-10.01342 4.23102,-4.23102 10.15445,-4.23102 5.92343,0 10.15445,4.23102 4.23102,4.08999 4.23102,10.01342 0,5.92343 -4.23102,10.15445 -4.23102,4.08999 -10.15445,4.08999 z m 0.14103,2.82068 q 5.92343,0 10.01342,4.23102 4.23102,4.23102 4.23102,10.15445 v 34.83541 q 0,5.92343 -4.23102,10.15445 -4.08999,4.08999 -10.01342,4.08999 -5.92343,0 -10.15445,-4.08999 -4.23102,-4.23102 -4.23102,-10.15445 v -34.83541 q 0,-5.92343 4.23102,-10.15445 4.23102,-4.23102 10.15445,-4.23102 z" />
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -1,30 +0,0 @@
/**
* Admin
*/
import VueRouter from 'vue-router';
// Style
import './style.styl';
import init from '../init';
import Index from './views/index.vue';
import NotFound from '../common/views/pages/not-found.vue';
init(launch => {
document.title = 'Admin';
// Init router
const router = new VueRouter({
mode: 'history',
base: '/admin/',
routes: [
{ path: '/:page', component: Index },
{ path: '/', redirect: '/dashboard' },
{ path: '*', component: NotFound }
]
});
// Launch the app
launch(router);
});

View File

@ -1,6 +0,0 @@
@import "../app"
@import "../reset"
html
height 100%
background var(--bg)

View File

@ -1,83 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faExclamationCircle"/> {{ $t('title') }}</template>
<section class="fit-top">
<sequential-entrance animation="entranceFromTop" delay="25">
<div v-for="report in userReports" :key="report.id" class="haexwsjc">
<ui-horizon-group inputs>
<ui-input :value="report.user | acct" type="text" readonly>
<span>{{ $t('target') }}</span>
</ui-input>
<ui-input :value="report.reporter | acct" type="text" readonly>
<span>{{ $t('reporter') }}</span>
</ui-input>
</ui-horizon-group>
<ui-textarea :value="report.comment" readonly>
<span>{{ $t('details') }}</span>
</ui-textarea>
<ui-button @click="removeReport(report)">{{ $t('remove-report') }}</ui-button>
</div>
</sequential-entrance>
<ui-button v-if="existMore" @click="fetchUserReports">{{ $t('@.load-more') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/abuse.vue'),
data() {
return {
limit: 10,
untilId: undefined,
userReports: [],
existMore: false,
faExclamationCircle
};
},
mounted() {
this.fetchUserReports();
},
methods: {
fetchUserReports() {
this.$root.api('admin/abuse-user-reports', {
untilId: this.untilId,
limit: this.limit + 1
}).then(reports => {
if (reports.length == this.limit + 1) {
reports.pop();
this.existMore = true;
} else {
this.existMore = false;
}
this.userReports = this.userReports.concat(reports);
this.untilId = this.userReports[this.userReports.length - 1].id;
});
},
removeReport(report) {
this.$root.api('admin/remove-abuse-user-report', {
reportId: report.id
}).then(() => {
this.userReports = this.userReports.filter(r => r.id != report.id);
});
}
}
});
</script>
<style lang="stylus" scoped>
.haexwsjc
padding-bottom 16px
border-bottom solid 1px var(--faceDivider)
</style>

View File

@ -1,91 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faBroadcastTower"/> {{ $t('announcements') }}</template>
<section v-for="(announcement, i) in announcements" class="fit-top">
<ui-input v-model="announcement.title" @change="save">
<span>{{ $t('title') }}</span>
</ui-input>
<ui-textarea v-model="announcement.text">
<span>{{ $t('text') }}</span>
</ui-textarea>
<ui-input v-model="announcement.image">
<span>{{ $t('image-url') }}</span>
</ui-input>
<ui-horizon-group class="fit-bottom">
<ui-button @click="save()"><fa :icon="['far', 'save']"/> {{ $t('save') }}</ui-button>
<ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> {{ $t('remove') }}</ui-button>
</ui-horizon-group>
</section>
<section>
<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('add') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faBroadcastTower, faPlus } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/announcements.vue'),
data() {
return {
announcements: [],
faBroadcastTower, faPlus
};
},
created() {
this.$root.getMeta().then(meta => {
this.announcements = meta.announcements;
});
},
methods: {
add() {
this.announcements.unshift({
title: '',
text: '',
image: null
});
},
remove(i) {
this.$root.dialog({
type: 'warning',
text: this.$t('_remove.are-you-sure').replace('$1', this.announcements.find((_, j) => j == i).title),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.announcements = this.announcements.filter((_, j) => j !== i);
this.save(true);
this.$root.dialog({
type: 'success',
text: this.$t('_remove.removed')
});
});
},
save(silent) {
this.$root.api('admin/update-meta', {
announcements: this.announcements
}).then(() => {
if (!silent) {
this.$root.dialog({
type: 'success',
text: this.$t('saved')
});
}
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
}
}
});
</script>

View File

@ -1,109 +0,0 @@
<template>
<div class="hyhctythnmwihguaaapnbrbszsjqxpio">
<table>
<thead>
<tr>
<th><fa :icon="faExchangeAlt"/> In/Out</th>
<th><fa :icon="faBolt"/> Activity</th>
<th><fa icon="server"/> Host</th>
<th><fa icon="user"/> Actor</th>
</tr>
</thead>
<tbody>
<tr v-for="log in logs" :key="log.id">
<td :class="log.direction">{{ log.direction == 'in' ? '<' : '>' }} {{ log.direction }}</td>
<td>{{ log.activity }}</td>
<td>{{ log.host }}</td>
<td>@{{ log.actor }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt, faExchangeAlt } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
data() {
return {
logs: [],
connection: null,
faBolt, faExchangeAlt
};
},
mounted() {
this.connection = this.$root.stream.useSharedConnection('apLog');
this.connection.on('log', this.onLog);
this.connection.on('logs', this.onLogs);
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 50
});
},
beforeDestroy() {
this.connection.dispose();
},
methods: {
onLog(log) {
log.id = Math.random();
this.logs.unshift(log);
if (this.logs.length > 50) this.logs.pop();
},
onLogs(logs) {
for (const log of logs.reverse()) {
this.onLog(log)
}
}
}
});
</script>
<style lang="stylus" scoped>
.hyhctythnmwihguaaapnbrbszsjqxpio
display block
padding 12px 16px 16px 16px
height 250px
overflow auto
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--adminDashboardCardBg)
border-radius 8px
> table
width 100%
max-width 100%
overflow auto
border-spacing 0
border-collapse collapse
color var(--adminDashboardCardFg)
font-size 14px
thead
border-bottom solid 1px var(--adminDashboardCardDivider)
tr
th
font-weight normal
text-align left
tbody
tr
&:nth-child(odd)
background rgba(0, 0, 0, 0.025)
th, td
padding 8px 16px
min-width 128px
td.in
color #d26755
td.out
color #55bb83
</style>

View File

@ -1,185 +0,0 @@
<template>
<div class="zyknedwtlthezamcjlolyusmipqmjgxz">
<div>
<header>
<span><fa icon="microchip"/> CPU <span>{{ cpuP }}%</span></span>
<span v-if="meta">{{ meta.cpu.model }}</span>
</header>
<div ref="cpu"></div>
</div>
<div>
<header>
<span><fa icon="memory"/> MEM <span>{{ memP }}%</span></span>
<span v-if="meta"></span>
</header>
<div ref="mem"></div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import ApexCharts from 'apexcharts';
export default Vue.extend({
props: ['connection'],
data() {
return {
stats: [],
cpuChart: null,
memChart: null,
cpuP: '',
memP: '',
meta: null
};
},
watch: {
stats(stats) {
this.cpuChart.updateSeries([{
data: stats.map((x, i) => ({ x: i, y: x.cpu_usage }))
}]);
this.memChart.updateSeries([{
data: stats.map((x, i) => ({ x: i, y: (x.mem.used / x.mem.total) }))
}]);
}
},
mounted() {
this.$root.getMeta().then(meta => {
this.meta = meta;
});
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 200
});
const chartOpts = {
chart: {
type: 'area',
height: 200,
animations: {
dynamicAnimation: {
enabled: false
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
stroke: {
curve: 'straight',
width: 2
},
tooltip: {
enabled: false
},
series: [{
data: []
}],
xaxis: {
type: 'numeric',
labels: {
show: false
},
tooltip: {
enabled: false
}
},
yaxis: {
show: false,
min: 0,
max: 1
}
};
this.cpuChart = new ApexCharts(this.$refs.cpu, chartOpts);
this.memChart = new ApexCharts(this.$refs.mem, chartOpts);
this.cpuChart.render();
this.memChart.render();
},
beforeDestroy() {
this.connection.off('stats', this.onStats);
this.connection.off('statsLog', this.onStatsLog);
this.cpuChart.destroy();
this.memChart.destroy();
},
methods: {
onStats(stats) {
this.stats.push(stats);
if (this.stats.length > 200) this.stats.shift();
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
},
onStatsLog(statsLog) {
for (const stats of statsLog.reverse()) {
this.onStats(stats);
}
}
}
});
</script>
<style lang="stylus" scoped>
.zyknedwtlthezamcjlolyusmipqmjgxz
display flex
> div
display block
flex 1
padding 20px 12px 0 12px
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--face)
border-radius 8px
&:first-child
margin-right 16px
> header
display flex
padding 0 8px
margin-bottom -16px
color var(--adminDashboardCardFg)
font-size 14px
> span
&:last-child
margin-left auto
opacity 0.7
> span
opacity 0.7
> div
margin-bottom -10px
@media (max-width 1000px)
display block
margin-bottom 26px
> div
&:first-child
margin-right 0
margin-bottom 26px
</style>

View File

@ -1,196 +0,0 @@
<template>
<div class="mzxlfysy">
<div>
<header>
<span><fa :icon="faInbox"/> In</span>
<span v-if="latestStats">{{ latestStats.inbox.activeSincePrevTick | number }} / {{ latestStats.inbox.delayed | number }}</span>
</header>
<div ref="in"></div>
</div>
<div>
<header>
<span><fa :icon="faPaperPlane"/> Out</span>
<span v-if="latestStats">{{ latestStats.deliver.activeSincePrevTick | number }} / {{ latestStats.deliver.delayed | number }}</span>
</header>
<div ref="out"></div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { faInbox } from '@fortawesome/free-solid-svg-icons';
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
import ApexCharts from 'apexcharts';
const limit = 150;
export default Vue.extend({
data() {
return {
stats: [],
inChart: null,
outChart: null,
faInbox, faPaperPlane
};
},
computed: {
latestStats(): any {
return this.stats[this.stats.length - 1];
}
},
watch: {
stats(stats) {
this.inChart.updateSeries([{
data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick }))
}, {
data: stats.map((x, i) => ({ x: i, y: x.inbox.active }))
}, {
data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting }))
}, {
data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed }))
}]);
this.outChart.updateSeries([{
data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick }))
}, {
data: stats.map((x, i) => ({ x: i, y: x.deliver.active }))
}, {
data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting }))
}, {
data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
}]);
}
},
mounted() {
const chartOpts = {
chart: {
type: 'area',
height: 200,
animations: {
dynamicAnimation: {
enabled: false
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
stroke: {
curve: 'straight',
width: 2
},
tooltip: {
enabled: false
},
legend: {
show: false
},
colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'],
series: [{ data: [] }, { data: [] }, { data: [] }, { data: [] }] as any,
xaxis: {
type: 'numeric',
labels: {
show: false
},
tooltip: {
enabled: false
}
},
yaxis: {
show: false,
min: 0,
}
};
this.inChart = new ApexCharts(this.$refs.in, chartOpts);
this.outChart = new ApexCharts(this.$refs.out, chartOpts);
this.inChart.render();
this.outChart.render();
const connection = this.$root.stream.useSharedConnection('queueStats');
connection.on('stats', this.onStats);
connection.on('statsLog', this.onStatsLog);
connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: limit
});
this.$once('hook:beforeDestroy', () => {
connection.dispose();
this.inChart.destroy();
this.outChart.destroy();
});
},
methods: {
onStats(stats) {
this.stats.push(stats);
if (this.stats.length > limit) this.stats.shift();
},
onStatsLog(statsLog) {
for (const stats of statsLog.reverse()) {
this.onStats(stats);
}
}
}
});
</script>
<style lang="stylus" scoped>
.mzxlfysy
display flex
> div
display block
flex 1
padding 20px 12px 0 12px
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--face)
border-radius 8px
&:first-child
margin-right 16px
> header
display flex
padding 0 8px
margin-bottom -16px
color var(--adminDashboardCardFg)
font-size 14px
> span
&:last-child
margin-left auto
opacity 0.7
> span
opacity 0.7
> div
margin-bottom -10px
@media (max-width 1000px)
display block
margin-bottom 26px
> div
&:first-child
margin-right 0
margin-bottom 26px
</style>

View File

@ -1,289 +0,0 @@
<template>
<div class="obdskegsannmntldydackcpzezagxqfy">
<header v-if="meta">
<p><b>Misskey</b><span>{{ meta.version }}</span></p>
<p><b>Machine</b><span>{{ meta.machine }}</span></p>
<p><b>OS</b><span>{{ meta.os }}</span></p>
<p><b>Node</b><span>{{ meta.node }}</span></p>
<p>{{ $t('@.ai-chan-kawaii') }}</p>
</header>
<marquee-text v-if="instances.length > 0" class="instances" :repeat="10" :duration="60">
<span v-for="instance in instances" class="instance">
<b :style="{ background: instance.bg }">{{ instance.host }}</b>{{ instance.notesCount | number }} / {{ instance.usersCount | number }}
</span>
</marquee-text>
<div v-if="stats" class="stats">
<div>
<div>
<div><fa icon="user"/></div>
<div>
<span>{{ $t('accounts') }}</span>
<b>{{ stats.originalUsersCount | number }}</b>
</div>
</div>
<div>
<span><fa icon="home"/> {{ $t('this-instance') }}</span>
<span @click="setChartSrc('users')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
<div>
<div>
<div><fa icon="pencil-alt"/></div>
<div>
<span>{{ $t('notes') }}</span>
<b>{{ stats.originalNotesCount | number }}</b>
</div>
</div>
<div>
<span><fa icon="home"/> {{ $t('this-instance') }}</span>
<span @click="setChartSrc('notes')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
<div>
<div>
<div><fa :icon="faDatabase"/></div>
<div>
<span>{{ $t('drive') }}</span>
<b>{{ stats.driveUsageLocal | bytes }}</b>
</div>
</div>
<div>
<span><fa icon="home"/> {{ $t('this-instance') }}</span>
<span @click="setChartSrc('drive')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
<div>
<div>
<div><fa :icon="['far', 'hdd']"/></div>
<div>
<span>{{ $t('instances') }}</span>
<b>{{ stats.instances | number }}</b>
</div>
</div>
<div>
<span><fa icon="globe"/> {{ $t('federated') }}</span>
<span @click="setChartSrc('federation-instances-total')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
</div>
<div class="charts">
<x-charts ref="charts"/>
</div>
<div class="queue">
<x-queue/>
</div>
<div class="cpu-memory">
<x-cpu-memory :connection="connection"/>
</div>
<div class="ap">
<x-ap-log/>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import XCpuMemory from "./dashboard.cpu-memory.vue";
import XQueue from "./dashboard.queue-charts.vue";
import XCharts from "./dashboard.charts.vue";
import XApLog from "./dashboard.ap-log.vue";
import { faDatabase } from '@fortawesome/free-solid-svg-icons';
import MarqueeText from 'vue-marquee-text-component';
import randomColor from 'randomcolor';
export default Vue.extend({
i18n: i18n('admin/views/dashboard.vue'),
components: {
XCpuMemory,
XQueue,
XCharts,
XApLog,
MarqueeText
},
data() {
return {
stats: null,
connection: null,
meta: null,
instances: [],
clock: null,
faDatabase
};
},
created() {
this.connection = this.$root.stream.useSharedConnection('serverStats');
this.updateStats();
this.clock = setInterval(this.updateStats, 3000);
this.$root.getMeta().then(meta => {
this.meta = meta;
});
this.$root.api('federation/instances', {
sort: '+notes'
}).then(instances => {
for (const i of instances) {
i.bg = randomColor({
seed: i.host,
luminosity: 'dark'
});
}
this.instances = instances;
});
},
beforeDestroy() {
this.connection.dispose();
clearInterval(this.clock);
},
methods: {
setChartSrc(src) {
this.$refs.charts.setSrc(src);
},
updateStats() {
this.$root.api('stats', {}, true).then(stats => {
this.stats = stats;
});
}
}
});
</script>
<style lang="stylus" scoped>
.obdskegsannmntldydackcpzezagxqfy
padding 16px
@media (min-width 500px)
padding 16px
> header
display flex
padding-bottom 16px
border-bottom solid 1px var(--adminDashboardHeaderBorder)
color var(--adminDashboardHeaderFg)
font-size 14px
white-space nowrap
@media (max-width 1000px)
display none
> p
display block
margin 0 32px 0 0
overflow hidden
text-overflow ellipsis
> b
&:after
content ':'
margin-right 8px
&:last-child
margin-left auto
margin-right 0
> .instances
padding 16px
color var(--adminDashboardHeaderFg)
font-size 13px
>>> .instance
margin 0 10px
> b
padding 2px 6px
margin-right 4px
border-radius 4px
color #fff
> .stats
display flex
justify-content space-between
margin-bottom 16px
> div
flex 1
margin-right 16px
color var(--adminDashboardCardFg)
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--adminDashboardCardBg)
border-radius 8px
&:last-child
margin-right 0
> div:first-child
display flex
align-items center
text-align center
&:last-child
margin-right 0
> div:first-child
padding 16px 24px
font-size 28px
> div:last-child
flex 1
padding 16px 32px 16px 0
text-align right
> span
font-size 70%
opacity 0.7
> b
display block
> div:last-child
display flex
padding 6px 16px
border-top solid 1px var(--adminDashboardCardDivider)
> span
font-size 70%
opacity 0.7
&:last-child
margin-left auto
cursor pointer
@media (max-width 900px)
display grid
grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr
gap 16px
> div
margin-right 0
@media (max-width 500px)
display block
> div:not(:last-child)
margin-bottom 16px
> .charts
margin-bottom 16px
> .queue
margin-bottom 16px
> .cpu-memory
margin-bottom 16px
</style>

View File

@ -1,61 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faDatabase"/> {{ $t('tables') }}</template>
<section v-if="tables">
<div v-for="table in Object.keys(tables)"><b>{{ table }}</b> {{ tables[table].count | number }} {{ tables[table].size | bytes }}</div>
</section>
<section>
<header><fa :icon="faBroom"/> {{ $t('vacuum') }}</header>
<ui-info>{{ $t('vacuum-info') }}</ui-info>
<ui-switch v-model="fullVacuum">FULL</ui-switch>
<ui-switch v-model="analyzeVacuum">ANALYZE</ui-switch>
<ui-button @click="vacuum()"><fa :icon="faBroom"/> {{ $t('vacuum') }}</ui-button>
<ui-info warn>{{ $t('vacuum-exclamation') }}</ui-info>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faDatabase, faBroom } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/db.vue'),
data() {
return {
tables: null,
fullVacuum: true,
analyzeVacuum: true,
faDatabase, faBroom
};
},
mounted() {
this.fetch();
},
methods: {
fetch() {
this.$root.api('admin/get-table-stats').then(tables => {
this.tables = tables;
});
},
vacuum() {
this.$root.api('admin/vacuum', {
full: this.fullVacuum,
analyze: this.analyzeVacuum,
}).then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
});
},
}
});
</script>

View File

@ -1,292 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faTerminal"/> {{ $t('operation') }}</template>
<section class="fit-top">
<ui-input v-model="target" type="text">
<span>{{ $t('fileid-or-url') }}</span>
</ui-input>
<ui-horizon-group>
<ui-button @click="findAndToggleSensitive(true)"><fa :icon="faEyeSlash"/> {{ $t('mark-as-sensitive') }}</ui-button>
<ui-button @click="findAndToggleSensitive(false)"><fa :icon="faEye"/> {{ $t('unmark-as-sensitive') }}</ui-button>
</ui-horizon-group>
<ui-button @click="findAndDel()"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
<ui-button @click="show()"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
<ui-textarea v-if="file" :value="file | json5" readonly tall style="margin-top:16px;"></ui-textarea>
</section>
<section>
<ui-button @click="cleanUp()"><fa :icon="faTrashAlt"/> {{ $t('clean-up') }}</ui-button>
<ui-button @click="cleanRemoteFiles()"><fa :icon="faTrashAlt"/> {{ $t('clean-remote-files') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faCloud"/> {{ $t('@.drive') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-select v-model="sort">
<template #label>{{ $t('sort.title') }}</template>
<option value="-createdAt">{{ $t('sort.createdAtAsc') }}</option>
<option value="+createdAt">{{ $t('sort.createdAtDesc') }}</option>
<option value="-size">{{ $t('sort.sizeAsc') }}</option>
<option value="+size">{{ $t('sort.sizeDesc') }}</option>
</ui-select>
<ui-select v-model="origin">
<template #label>{{ $t('origin.title') }}</template>
<option value="combined">{{ $t('origin.combined') }}</option>
<option value="local">{{ $t('origin.local') }}</option>
<option value="remote">{{ $t('origin.remote') }}</option>
</ui-select>
</ui-horizon-group>
<sequential-entrance animation="entranceFromTop" delay="25">
<div class="kidvdlkg" v-for="file in files">
<div @click="file._open = !file._open">
<div>
<x-file-thumbnail class="thumbnail" :file="file" fit="contain" @click="showFileMenu(file)"/>
</div>
<div>
<header>
<b>{{ file.name }}</b>
<span class="username">@{{ file.user | acct }}</span>
</header>
<div>
<div>
<span style="margin-right:16px;">{{ file.type }}</span>
<span>{{ file.size | bytes }}</span>
</div>
<div><mk-time :time="file.createdAt" mode="detail"/></div>
</div>
</div>
</div>
<div v-show="file._open">
<ui-input readonly :value="file.url"></ui-input>
<ui-horizon-group>
<ui-button @click="toggleSensitive(file)" v-if="file.isSensitive"><fa :icon="faEye"/> {{ $t('unmark-as-sensitive') }}</ui-button>
<ui-button @click="toggleSensitive(file)" v-else><fa :icon="faEyeSlash"/> {{ $t('mark-as-sensitive') }}</ui-button>
<ui-button @click="del(file)"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
</ui-horizon-group>
</div>
</div>
</sequential-entrance>
<ui-button v-if="existMore" @click="fetch">{{ $t('@.load-more') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faCloud, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
import XFileThumbnail from '../../common/views/components/drive-file-thumbnail.vue';
export default Vue.extend({
i18n: i18n('admin/views/drive.vue'),
components: {
XFileThumbnail
},
data() {
return {
file: null,
target: null,
sort: '+createdAt',
origin: 'combined',
limit: 10,
offset: 0,
files: [],
existMore: false,
faCloud, faTrashAlt, faEye, faEyeSlash, faTerminal, faSearch
};
},
watch: {
sort() {
this.files = [];
this.offset = 0;
this.fetch();
},
origin() {
this.files = [];
this.offset = 0;
this.fetch();
}
},
mounted() {
this.fetch();
},
methods: {
async fetchFile() {
try {
return await this.$root.api('drive/files/show', this.target.startsWith('http') ? { url: this.target } : { fileId: this.target });
} catch (e) {
if (e == 'file-not-found') {
this.$root.dialog({
type: 'error',
text: this.$t('file-not-found')
});
} else {
this.$root.dialog({
type: 'error',
text: e.toString()
});
}
}
},
fetch() {
this.$root.api('admin/drive/files', {
origin: this.origin,
sort: this.sort,
offset: this.offset,
limit: this.limit + 1
}).then(files => {
if (files.length == this.limit + 1) {
files.pop();
this.existMore = true;
} else {
this.existMore = false;
}
for (const x of files) {
x._open = false;
}
this.files = this.files.concat(files);
this.offset += this.limit;
});
},
async del(file: any) {
const process = async () => {
await this.$root.api('drive/files/delete', { fileId: file.id });
this.$root.dialog({
type: 'success',
text: this.$t('deleted')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
toggleSensitive(file: any) {
this.$root.api('drive/files/update', {
fileId: file.id,
isSensitive: !file.isSensitive
}).then(() => {
file.isSensitive = !file.isSensitive;
});
},
async show() {
const file = await this.fetchFile();
this.$root.api('admin/drive/show-file', { fileId: file.id }).then(info => {
this.file = info;
});
},
async findAndToggleSensitive(sensitive) {
const process = async () => {
const file = await this.fetchFile();
await this.$root.api('drive/files/update', {
fileId: file.id,
isSensitive: sensitive
});
this.$root.dialog({
type: 'success',
text: sensitive ? this.$t('marked-as-sensitive') : this.$t('unmarked-as-sensitive')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
async findAndDel() {
const process = async () => {
const file = await this.fetchFile();
await this.$root.api('drive/files/delete', { fileId: file.id });
this.$root.dialog({
type: 'success',
text: this.$t('deleted')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
cleanRemoteFiles() {
this.$root.dialog({
type: 'warning',
text: this.$t('clean-remote-files-are-you-sure'),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('admin/drive/clean-remote-files');
this.$root.dialog({
type: 'success',
splash: true
});
});
},
cleanUp() {
this.$root.api('admin/drive/cleanup');
this.$root.dialog({
type: 'success',
splash: true
});
}
}
});
</script>
<style lang="stylus" scoped>
.kidvdlkg
padding 16px 0
border-top solid 1px var(--faceDivider)
> div:first-child
display flex
cursor pointer
> div:nth-child(1)
> .thumbnail
display flex
width 64px
height 64px
background-size cover
background-position center center
> div:nth-child(2)
flex 1
padding-left 16px
@media (max-width 500px)
font-size 14px
> header
word-break break-word
> .username
margin-left 8px
opacity 0.7
</style>

View File

@ -1,185 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa icon="plus"/> {{ $t('add-emoji.title') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-input v-model="name">
<span>{{ $t('add-emoji.name') }}</span>
<template #desc>{{ $t('add-emoji.name-desc') }}</template>
</ui-input>
<ui-input v-model="category" :datalist="categoryList">
<span>{{ $t('add-emoji.category') }}</span>
</ui-input>
<ui-input v-model="aliases">
<span>{{ $t('add-emoji.aliases') }}</span>
<template #desc>{{ $t('add-emoji.aliases-desc') }}</template>
</ui-input>
</ui-horizon-group>
<ui-input v-model="url">
<template #icon><fa icon="link"/></template>
<span>{{ $t('add-emoji.url') }}</span>
</ui-input>
<ui-info>{{ $t('add-emoji.info') }}</ui-info>
<ui-button @click="add">{{ $t('add-emoji.add') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faGrin"/> {{ $t('emojis.title') }}</template>
<section v-for="emoji in emojis" :key="emoji.name" class="oryfrbft">
<div>
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
</div>
<div>
<ui-horizon-group>
<ui-input v-model="emoji.name">
<span>{{ $t('add-emoji.name') }}</span>
</ui-input>
<ui-input v-model="emoji.category" :datalist="categoryList">
<span>{{ $t('add-emoji.category') }}</span>
</ui-input>
<ui-input v-model="emoji.aliases">
<span>{{ $t('add-emoji.aliases') }}</span>
</ui-input>
</ui-horizon-group>
<ui-input v-model="emoji.url">
<template #icon><fa icon="link"/></template>
<span>{{ $t('add-emoji.url') }}</span>
</ui-input>
<ui-horizon-group class="fit-bottom">
<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> {{ $t('emojis.update') }}</ui-button>
<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> {{ $t('emojis.remove') }}</ui-button>
</ui-horizon-group>
</div>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faGrin } from '@fortawesome/free-regular-svg-icons';
import { unique } from '../../../../prelude/array';
export default Vue.extend({
i18n: i18n('admin/views/emoji.vue'),
data() {
return {
name: '',
category: '',
url: '',
aliases: '',
emojis: [],
faGrin
};
},
mounted() {
this.fetchEmojis();
},
computed: {
categoryList() {
return unique(this.emojis.map((x: any) => x.category || '').filter((x: string) => x !== ''));
}
},
methods: {
add() {
this.$root.api('admin/emoji/add', {
name: this.name,
category: this.category,
url: this.url,
aliases: this.aliases.split(' ').filter(x => x.length > 0)
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('add-emoji.added')
});
this.fetchEmojis();
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
},
fetchEmojis() {
this.$root.api('admin/emoji/list').then(emojis => {
for (const e of emojis) {
e.aliases = (e.aliases || []).join(' ');
}
this.emojis = emojis;
});
},
updateEmoji(emoji) {
this.$root.api('admin/emoji/update', {
id: emoji.id,
name: emoji.name,
category: emoji.category,
url: emoji.url,
aliases: emoji.aliases.split(' ').filter(x => x.length > 0)
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('updated')
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
},
removeEmoji(emoji) {
this.$root.dialog({
type: 'warning',
text: this.$t('remove-emoji.are-you-sure').replace('$1', emoji.name),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('admin/emoji/remove', {
id: emoji.id
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('remove-emoji.removed')
});
this.fetchEmojis();
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
});
}
}
});
</script>
<style lang="stylus" scoped>
.oryfrbft
@media (min-width 500px)
display flex
> div:first-child
@media (max-width 500px)
padding-bottom 16px
> img
vertical-align bottom
> div:last-child
flex 1
@media (min-width 500px)
padding-left 16px
</style>

View File

@ -1,553 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faTerminal"/> {{ $t('instance') }}</template>
<section class="fit-top">
<ui-input class="target" v-model="target" type="text" @enter="showInstance()">
<span>{{ $t('host') }}</span>
<template #prefix><fa :icon="faServer"/></template>
</ui-input>
<ui-button @click="showInstance()"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
<div class="instance" v-if="instance">
<ui-horizon-group inputs>
<ui-input :value="instance.host" type="text" readonly>
<span>{{ $t('host') }}</span>
<template #prefix><fa :icon="faServer"/></template>
</ui-input>
<ui-input :value="instance.caughtAt | date" type="text" readonly>
<span>{{ $t('caught-at') }}</span>
<template #prefix><fa :icon="faCrosshairs"/></template>
</ui-input>
</ui-horizon-group>
<ui-horizon-group inputs>
<ui-input :value="instance.notesCount | number" type="text" readonly>
<span>{{ $t('notes') }}</span>
<template #prefix><fa :icon="faEnvelopeOpenText"/></template>
</ui-input>
<ui-input :value="instance.usersCount | number" type="text" readonly>
<span>{{ $t('users') }}</span>
<template #prefix><fa :icon="faUsers"/></template>
</ui-input>
</ui-horizon-group>
<ui-horizon-group inputs>
<ui-input :value="instance.followingCount | number" type="text" readonly>
<span>{{ $t('following') }}</span>
<template #prefix><fa :icon="faCaretDown"/></template>
</ui-input>
<ui-input :value="instance.followersCount | number" type="text" readonly>
<span>{{ $t('followers') }}</span>
<template #prefix><fa :icon="faCaretUp"/></template>
</ui-input>
</ui-horizon-group>
<ui-horizon-group inputs>
<ui-input :value="instance.latestRequestSentAt | date" type="text" readonly>
<span>{{ $t('latest-request-sent-at') }}</span>
<template #prefix><fa :icon="faPaperPlane"/></template>
</ui-input>
<ui-input :value="instance.latestStatus" type="text" readonly>
<span>{{ $t('status') }}</span>
<template #prefix><fa :icon="faTrafficLight"/></template>
</ui-input>
</ui-horizon-group>
<ui-input :value="instance.latestRequestReceivedAt | date" type="text" readonly>
<span>{{ $t('latest-request-received-at') }}</span>
<template #prefix><fa :icon="faInbox"/></template>
</ui-input>
<ui-switch v-model="instance.isMarkedAsClosed" @change="updateInstance()">{{ $t('marked-as-closed') }}</ui-switch>
<details>
<summary>{{ $t('charts') }}</summary>
<ui-horizon-group inputs>
<ui-select v-model="chartSrc">
<option value="requests">{{ $t('chart-srcs.requests') }}</option>
<option value="users">{{ $t('chart-srcs.users') }}</option>
<option value="users-total">{{ $t('chart-srcs.users-total') }}</option>
<option value="notes">{{ $t('chart-srcs.notes') }}</option>
<option value="notes-total">{{ $t('chart-srcs.notes-total') }}</option>
<option value="ff">{{ $t('chart-srcs.ff') }}</option>
<option value="ff-total">{{ $t('chart-srcs.ff-total') }}</option>
<option value="drive-usage">{{ $t('chart-srcs.drive-usage') }}</option>
<option value="drive-usage-total">{{ $t('chart-srcs.drive-usage-total') }}</option>
<option value="drive-files">{{ $t('chart-srcs.drive-files') }}</option>
<option value="drive-files-total">{{ $t('chart-srcs.drive-files-total') }}</option>
</ui-select>
<ui-select v-model="chartSpan">
<option value="hour">{{ $t('chart-spans.hour') }}</option>
<option value="day">{{ $t('chart-spans.day') }}</option>
</ui-select>
</ui-horizon-group>
<div ref="chart"></div>
</details>
<details>
<summary>{{ $t('delete-all-files') }}</summary>
<ui-button @click="deleteAllFiles()" style="margin-top: 16px;"><fa :icon="faTrashAlt"/> {{ $t('delete-all-files') }}</ui-button>
</details>
<details>
<summary>{{ $t('remove-all-following') }}</summary>
<ui-button @click="removeAllFollowing()" style="margin-top: 16px;"><fa :icon="faMinusCircle"/> {{ $t('remove-all-following') }}</ui-button>
<ui-info warn>{{ $t('remove-all-following-info', { host: instance.host }) }}</ui-info>
</details>
</div>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faServer"/> {{ $t('instances') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-select v-model="sort">
<template #label>{{ $t('sort') }}</template>
<option value="-caughtAt">{{ $t('sorts.caughtAtAsc') }}</option>
<option value="+caughtAt">{{ $t('sorts.caughtAtDesc') }}</option>
<option value="-lastCommunicatedAt">{{ $t('sorts.lastCommunicatedAtAsc') }}</option>
<option value="+lastCommunicatedAt">{{ $t('sorts.lastCommunicatedAtDesc') }}</option>
<option value="-notes">{{ $t('sorts.notesAsc') }}</option>
<option value="+notes">{{ $t('sorts.notesDesc') }}</option>
<option value="-users">{{ $t('sorts.usersAsc') }}</option>
<option value="+users">{{ $t('sorts.usersDesc') }}</option>
<option value="-following">{{ $t('sorts.followingAsc') }}</option>
<option value="+following">{{ $t('sorts.followingDesc') }}</option>
<option value="-followers">{{ $t('sorts.followersAsc') }}</option>
<option value="+followers">{{ $t('sorts.followersDesc') }}</option>
<option value="-driveUsage">{{ $t('sorts.driveUsageAsc') }}</option>
<option value="+driveUsage">{{ $t('sorts.driveUsageDesc') }}</option>
<option value="-driveFiles">{{ $t('sorts.driveFilesAsc') }}</option>
<option value="+driveFiles">{{ $t('sorts.driveFilesDesc') }}</option>
</ui-select>
<ui-select v-model="state">
<template #label>{{ $t('state') }}</template>
<option value="all">{{ $t('states.all') }}</option>
<option value="blocked">{{ $t('states.blocked') }}</option>
<option value="notResponding">{{ $t('states.not-responding') }}</option>
<option value="markedAsClosed">{{ $t('states.marked-as-closed') }}</option>
</ui-select>
</ui-horizon-group>
<div class="instances">
<header>
<span>{{ $t('host') }}</span>
<span>{{ $t('notes') }}</span>
<span>{{ $t('users') }}</span>
<span>{{ $t('following') }}</span>
<span>{{ $t('followers') }}</span>
<span>{{ $t('status') }}</span>
</header>
<div v-for="instance in instances" :style="{ opacity: instance.isNotResponding ? 0.5 : 1 }">
<a @click.prevent="showInstance(instance.host)" rel="nofollow noopener" target="_blank" :href="`https://${instance.host}`" :style="{ textDecoration: instance.isMarkedAsClosed ? 'line-through' : 'none' }">{{ instance.host }}</a>
<span>{{ instance.notesCount | number }}</span>
<span>{{ instance.usersCount | number }}</span>
<span>{{ instance.followingCount | number }}</span>
<span>{{ instance.followersCount | number }}</span>
<span>{{ instance.latestStatus }}</span>
</div>
</div>
<ui-info v-if="instances.length == limit">{{ $t('result-is-truncated', { n: limit }) }}</ui-info>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faBan"/> {{ $t('blocked-hosts') }}</template>
<section class="fit-top">
<ui-textarea v-model="blockedHosts">
<template #desc>{{ $t('blocked-hosts-info') }}</template>
</ui-textarea>
<ui-button @click="saveBlockedHosts">{{ $t('save') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
import { faTrashAlt, faBan, faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faTrafficLight, faInbox } from '@fortawesome/free-solid-svg-icons';
import ApexCharts from 'apexcharts';
import * as tinycolor from 'tinycolor2';
const chartLimit = 90;
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
const negate = arr => arr.map(x => -x);
export default Vue.extend({
i18n: i18n('admin/views/federation.vue'),
filters: {
date: v => v ? new Date(v).toLocaleString() : 'N/A'
},
data() {
return {
instance: null,
target: null,
sort: '+lastCommunicatedAt',
state: 'all',
limit: 100,
instances: [],
chart: null,
chartSrc: 'requests',
chartSpan: 'hour',
chartInstance: null,
blockedHosts: '',
faTrashAlt, faBan, faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faPaperPlane, faTrafficLight, faInbox
};
},
computed: {
data(): any {
if (this.chart == null) return null;
switch (this.chartSrc) {
case 'requests': return this.requestsChart();
case 'users': return this.usersChart(false);
case 'users-total': return this.usersChart(true);
case 'notes': return this.notesChart(false);
case 'notes-total': return this.notesChart(true);
case 'ff': return this.ffChart(false);
case 'ff-total': return this.ffChart(true);
case 'drive-usage': return this.driveUsageChart(false);
case 'drive-usage-total': return this.driveUsageChart(true);
case 'drive-files': return this.driveFilesChart(false);
case 'drive-files-total': return this.driveFilesChart(true);
}
},
stats(): any[] {
const stats =
this.chartSpan == 'day' ? this.chart.perDay :
this.chartSpan == 'hour' ? this.chart.perHour :
null;
return stats;
}
},
watch: {
sort() {
this.fetchInstances();
},
state() {
this.fetchInstances();
},
async instance() {
this.now = new Date();
const [perHour, perDay] = await Promise.all([
this.$root.api('charts/instance', { host: this.instance.host, limit: chartLimit, span: 'hour' }),
this.$root.api('charts/instance', { host: this.instance.host, limit: chartLimit, span: 'day' }),
]);
const chart = {
perHour: perHour,
perDay: perDay
};
this.chart = chart;
this.renderChart();
},
chartSrc() {
this.renderChart();
},
chartSpan() {
this.renderChart();
}
},
mounted() {
this.fetchInstances();
this.$root.getMeta().then(meta => {
this.blockedHosts = meta.blockedHosts.join('\n');
});
},
beforeDestroy() {
this.chartInstance.destroy();
},
methods: {
showInstance(target?: string) {
this.$root.api('federation/show-instance', {
host: target || this.target
}).then(instance => {
if (instance == null) {
this.$root.dialog({
type: 'error',
text: this.$t('instance-not-registered')
});
} else {
this.instance = instance;
this.target = '';
}
});
},
fetchInstances() {
this.instances = [];
this.$root.api('federation/instances', {
blocked: this.state === 'blocked' ? true : null,
notResponding: this.state === 'notResponding' ? true : null,
markedAsClosed: this.state === 'markedAsClosed' ? true : null,
sort: this.sort,
limit: this.limit
}).then(instances => {
this.instances = instances;
});
},
removeAllFollowing() {
this.$root.api('admin/federation/remove-all-following', {
host: this.instance.host
}).then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
});
},
deleteAllFiles() {
this.$root.api('admin/federation/delete-all-files', {
host: this.instance.host
}).then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
});
},
updateInstance() {
this.$root.api('admin/federation/update-instance', {
host: this.instance.host,
isBlocked: this.instance.isBlocked || false,
isClosed: this.instance.isMarkedAsClosed || false
});
},
setSrc(src) {
this.chartSrc = src;
},
renderChart() {
if (this.chartInstance) {
this.chartInstance.destroy();
}
this.chartInstance = new ApexCharts(this.$refs.chart, {
chart: {
type: 'area',
height: 300,
animations: {
dynamicAnimation: {
enabled: false
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
stroke: {
curve: 'straight',
width: 2
},
tooltip: {
theme: this.$store.state.device.darkmode ? 'dark' : 'light'
},
legend: {
labels: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
},
},
xaxis: {
type: 'datetime',
labels: {
style: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
}
},
axisBorder: {
color: 'rgba(0, 0, 0, 0.1)'
},
axisTicks: {
color: 'rgba(0, 0, 0, 0.1)'
},
},
yaxis: {
labels: {
formatter: this.data.bytes ? v => Vue.filter('bytes')(v, 0) : v => Vue.filter('number')(v),
style: {
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
}
}
},
series: this.data.series
});
this.chartInstance.render();
},
getDate(i: number) {
const y = this.now.getFullYear();
const m = this.now.getMonth();
const d = this.now.getDate();
const h = this.now.getHours();
return (
this.chartSpan == 'day' ? new Date(y, m, d - i) :
this.chartSpan == 'hour' ? new Date(y, m, d, h - i) :
null
);
},
format(arr) {
return arr.map((v, i) => ({ x: this.getDate(i).getTime(), y: v }));
},
requestsChart(): any {
return {
series: [{
name: 'Incoming',
data: this.format(this.stats.requests.received)
}, {
name: 'Outgoing (succeeded)',
data: this.format(this.stats.requests.succeeded)
}, {
name: 'Outgoing (failed)',
data: this.format(this.stats.requests.failed)
}]
};
},
usersChart(total: boolean): any {
return {
series: [{
name: 'Users',
type: 'area',
data: this.format(total
? this.stats.users.total
: sum(this.stats.users.inc, negate(this.stats.users.dec))
)
}]
};
},
notesChart(total: boolean): any {
return {
series: [{
name: 'Notes',
type: 'area',
data: this.format(total
? this.stats.notes.total
: sum(this.stats.notes.inc, negate(this.stats.notes.dec))
)
}]
};
},
ffChart(total: boolean): any {
return {
series: [{
name: 'Following',
type: 'area',
data: this.format(total
? this.stats.following.total
: sum(this.stats.following.inc, negate(this.stats.following.dec))
)
}, {
name: 'Followers',
type: 'area',
data: this.format(total
? this.stats.followers.total
: sum(this.stats.followers.inc, negate(this.stats.followers.dec))
)
}]
};
},
driveUsageChart(total: boolean): any {
return {
bytes: true,
series: [{
name: 'Drive usage',
type: 'area',
data: this.format(total
? this.stats.drive.totalUsage
: sum(this.stats.drive.incUsage, negate(this.stats.drive.decUsage))
)
}]
};
},
driveFilesChart(total: boolean): any {
return {
series: [{
name: 'Drive files',
type: 'area',
data: this.format(total
? this.stats.drive.totalFiles
: sum(this.stats.drive.incFiles, negate(this.stats.drive.decFiles))
)
}]
};
},
saveBlockedHosts() {
this.$root.api('admin/update-meta', {
blockedHosts: this.blockedHosts ? this.blockedHosts.split('\n') : []
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('saved')
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
}
}
});
</script>
<style lang="stylus" scoped>
.target
margin-bottom 16px !important
.instances
width 100%
> header
display flex
> *
color var(--text)
font-weight bold
> div
display flex
> * > *
flex 1
overflow auto
&:first-child
min-width 200px
</style>

View File

@ -1,297 +0,0 @@
<template>
<div class="mk-admin" :class="{ isMobile }">
<header v-show="isMobile">
<button class="nav" @click="navOpend = true"><fa icon="bars"/></button>
<span>MisskeyMyAdmin</span>
</header>
<div class="nav-backdrop"
v-if="navOpend && isMobile"
@click="navOpend = false"
@touchstart="navOpend = false"
></div>
<nav v-show="navOpend">
<div class="mi">
<img svg-inline src="../assets/header-icon.svg"/>
</div>
<div class="me">
<img class="avatar" :src="$store.state.i.avatarUrl" alt="avatar"/>
<p class="name"><mk-user-name :user="$store.state.i"/></p>
</div>
<ul>
<li><router-link to="/dashboard" active-class="active"><fa icon="home" fixed-width/>{{ $t('dashboard') }}</router-link></li>
<li><router-link to="/instance" active-class="active"><fa icon="cog" fixed-width/>{{ $t('instance') }}</router-link></li>
<li><router-link to="/queue" active-class="active"><fa :icon="faTasks" fixed-width/>{{ $t('queue') }}</router-link></li>
<li><router-link to="/logs" active-class="active"><fa :icon="faStream" fixed-width/>{{ $t('logs') }}</router-link></li>
<li><router-link to="/db" active-class="active"><fa :icon="faDatabase" fixed-width/>{{ $t('db') }}</router-link></li>
<li><router-link to="/moderators" active-class="active"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</router-link></li>
<li><router-link to="/users" active-class="active"><fa icon="users" fixed-width/>{{ $t('users') }}</router-link></li>
<li><router-link to="/drive" active-class="active"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</router-link></li>
<li><router-link to="/federation" active-class="active"><fa :icon="faGlobe" fixed-width/>{{ $t('federation') }}</router-link></li>
<li><router-link to="/emoji" active-class="active"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</router-link></li>
<li><router-link to="/announcements" active-class="active"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</router-link></li>
<li><router-link to="/abuse" active-class="active"><fa :icon="faExclamationCircle" fixed-width/>{{ $t('abuse') }}</router-link></li>
</ul>
<div class="back-to-misskey">
<a href="/"><fa :icon="faArrowLeft"/> {{ $t('back-to-misskey') }}</a>
</div>
<div class="version">
<small>Misskey {{ version }}</small>
</div>
</nav>
<main>
<div class="page">
<div v-if="page == 'dashboard'"><x-dashboard/></div>
<div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'queue'"><x-queue/></div>
<div v-if="page == 'logs'"><x-logs/></div>
<div v-if="page == 'db'"><x-db/></div>
<div v-if="page == 'moderators'"><x-moderators/></div>
<div v-if="page == 'users'"><x-users/></div>
<div v-if="page == 'emoji'"><x-emoji/></div>
<div v-if="page == 'announcements'"><x-announcements/></div>
<div v-if="page == 'drive'"><x-drive/></div>
<div v-if="page == 'federation'"><x-federation/></div>
<div v-if="page == 'abuse'"><x-abuse/></div>
</div>
</main>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { version } from '../../config';
import XDashboard from './dashboard.vue';
import XInstance from './instance.vue';
import XQueue from './queue.vue';
import XLogs from './logs.vue';
import XDb from './db.vue';
import XModerators from './moderators.vue';
import XEmoji from './emoji.vue';
import XAnnouncements from './announcements.vue';
import XUsers from './users.vue';
import XDrive from './drive.vue';
import XAbuse from './abuse.vue';
import XFederation from './federation.vue';
import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks, faStream, faDatabase } from '@fortawesome/free-solid-svg-icons';
import { faGrin } from '@fortawesome/free-regular-svg-icons';
// Detect the user agent
const ua = navigator.userAgent.toLowerCase();
const isMobile = /mobile|iphone|ipad|android/.test(ua);
export default Vue.extend({
i18n: i18n('admin/views/index.vue'),
components: {
XDashboard,
XInstance,
XQueue,
XLogs,
XDb,
XModerators,
XEmoji,
XAnnouncements,
XUsers,
XDrive,
XAbuse,
XFederation,
},
provide: {
isMobile
},
data() {
return {
version,
isMobile,
navOpend: !isMobile,
faGrin,
faArrowLeft,
faHeadset,
faGlobe,
faExclamationCircle,
faTasks,
faStream,
faDatabase,
};
},
computed: {
page() {
return this.$route.params.page;
}
}
});
</script>
<style lang="stylus" scoped>
.mk-admin
$headerHeight = 48px
display flex
height 100%
> header
position fixed
top 0
z-index 10000
width 100%
color var(--mobileHeaderFg)
background-color var(--mobileHeaderBg)
box-shadow 0 1px 0 rgba(#000, 0.075)
&, *
user-select none
> span
display block
line-height $headerHeight
text-align center
> .nav
display block
position absolute
top 0
left 0
z-index 10001
padding 0
width $headerHeight
font-size 1.4em
line-height $headerHeight
border-right solid 1px rgba(#000, 0.1)
> [data-icon]
transition all 0.2s ease
> nav
position fixed
z-index 20001
top 0
left 0
width 250px
height 100vh
overflow auto
background #333
color #fff
> .mi
text-align center
> svg
width 24px
height 82px
vertical-align top
fill #fff
opacity 0.7
> .me
display flex
margin 0 16px 16px 16px
padding 16px 0
align-items center
border-top solid 1px #555
border-bottom solid 1px #555
> .avatar
height 48px
border-radius 100%
vertical-align middle
> .name
margin 0 16px
padding 0
color #fff
overflow hidden
text-overflow ellipsis
white-space nowrap
font-size 15px
> .back-to-misskey
margin 16px 16px 0 16px
padding 0
border-top solid 1px #555
> a
display block
padding 16px 4px
color inherit
text-decoration none
color #eee
font-size 15px
&:hover
color #fff
> [data-icon]
margin-right 6px
> .version
margin 0 16px 16px 16px
padding-top 16px
border-top solid 1px #555
text-align center
> small
opacity 0.7
> ul
margin 0
padding 0
list-style none
font-size 15px
> li > a
display block
padding 10px 16px
margin 0
user-select none
color #eee
transition margin-left 0.2s ease
&:hover
color #fff
> [data-icon]
margin-right 6px
&.active
margin-left 8px
color var(--primary) !important
&:after
content ""
display block
position absolute
top 0
right 0
bottom 0
margin auto 0
height 0
border-top solid 16px transparent
border-right solid 16px var(--bg)
border-bottom solid 16px transparent
border-left solid 16px transparent
> .nav-backdrop
position fixed
top 0
left 0
z-index 20000
width 100%
height 100%
background var(--mobileNavBackdrop)
> main
width 100%
padding 0 0 0 250px
> .page
max-width 1150px
@media (min-width 500px)
padding 16px
&.isMobile
> main
padding $headerHeight 0 0 0
</style>

View File

@ -1,519 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa icon="cog"/> {{ $t('instance') }}</template>
<section class="fit-top">
<ui-input :value="host" readonly>{{ $t('host') }}</ui-input>
<ui-input v-model="name">{{ $t('instance-name') }}</ui-input>
<ui-textarea v-model="description">{{ $t('instance-description') }}</ui-textarea>
<ui-input v-model="iconUrl"><template #icon><fa icon="link"/></template>{{ $t('icon-url') }}</ui-input>
<ui-input v-model="mascotImageUrl"><template #icon><fa icon="link"/></template>{{ $t('logo-url') }}</ui-input>
<ui-input v-model="bannerUrl"><template #icon><fa icon="link"/></template>{{ $t('banner-url') }}</ui-input>
<ui-input v-model="ToSUrl"><template #icon><fa icon="link"/></template>{{ $t('tos-url') }}</ui-input>
<details>
<summary>{{ $t('advanced-config') }}</summary>
<ui-input v-model="errorImageUrl"><template #icon><fa icon="link"/></template>{{ $t('error-image-url') }}</ui-input>
<ui-input v-model="languages"><template #icon><fa icon="language"/></template>{{ $t('languages') }}<template #desc>{{ $t('languages-desc') }}</template></ui-input>
<ui-input v-model="repositoryUrl"><template #icon><fa icon="link"/></template>{{ $t('repository-url') }}</ui-input>
<ui-input v-model="feedbackUrl"><template #icon><fa icon="link"/></template>{{ $t('feedback-url') }}</ui-input>
</details>
</section>
<section class="fit-bottom">
<header><fa :icon="faHeadset"/> {{ $t('maintainer-config') }}</header>
<ui-input v-model="maintainerName">{{ $t('maintainer-name') }}</ui-input>
<ui-input v-model="maintainerEmail" type="email"><template #icon><fa :icon="farEnvelope"/></template>{{ $t('maintainer-email') }}</ui-input>
</section>
<section>
<ui-switch v-model="disableRegistration">{{ $t('disable-registration') }}</ui-switch>
<ui-button v-if="disableRegistration" @click="invite">{{ $t('invite') }}</ui-button>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faPencilAlt"/> {{ $t('note-and-tl') }}</template>
<section class="fit-top fit-bottom">
<ui-input v-model="maxNoteTextLength">{{ $t('max-note-text-length') }}</ui-input>
</section>
<section>
<ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
<ui-switch v-model="disableGlobalTimeline">{{ $t('disable-global-timeline') }}</ui-switch>
<ui-info>{{ $t('disabling-timelines-info') }}</ui-info>
</section>
<section>
<ui-switch v-model="enableEmojiReaction">{{ $t('enable-emoji-reaction') }}</ui-switch>
<ui-switch v-model="useStarForReactionFallback">{{ $t('use-star-for-reaction-fallback') }}</ui-switch>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa icon="cloud"/> {{ $t('drive-config') }}</template>
<section>
<ui-switch v-model="useObjectStorage">{{ $t('use-object-storage') }}</ui-switch>
<template v-if="useObjectStorage">
<ui-info>
<i18n path="object-storage-s3-info">
<a href="https://docs.aws.amazon.com/general/latest/gr/rande.html" target="_blank">{{ $t('object-storage-s3-info-here') }}</a>
</i18n>
</ui-info>
<ui-info>{{ $t('object-storage-gcs-info') }}</ui-info>
<ui-input v-model="objectStorageBaseUrl" :disabled="!useObjectStorage">{{ $t('object-storage-base-url') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="objectStorageBucket" :disabled="!useObjectStorage">{{ $t('object-storage-bucket') }}</ui-input>
<ui-input v-model="objectStoragePrefix" :disabled="!useObjectStorage">{{ $t('object-storage-prefix') }}</ui-input>
</ui-horizon-group>
<ui-input v-model="objectStorageEndpoint" :disabled="!useObjectStorage">{{ $t('object-storage-endpoint') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="objectStorageRegion" :disabled="!useObjectStorage">{{ $t('object-storage-region') }}</ui-input>
<ui-input v-model="objectStoragePort" type="number" :disabled="!useObjectStorage">{{ $t('object-storage-port') }}</ui-input>
</ui-horizon-group>
<ui-horizon-group inputs>
<ui-input v-model="objectStorageAccessKey" :disabled="!useObjectStorage"><template #icon><fa icon="key"/></template>{{ $t('object-storage-access-key') }}</ui-input>
<ui-input v-model="objectStorageSecretKey" :disabled="!useObjectStorage"><template #icon><fa icon="key"/></template>{{ $t('object-storage-secret-key') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="objectStorageUseSSL" :disabled="!useObjectStorage">{{ $t('object-storage-use-ssl') }}</ui-switch>
</template>
</section>
<section>
<ui-switch v-model="cacheRemoteFiles">{{ $t('cache-remote-files') }}<template #desc>{{ $t('cache-remote-files-desc') }}</template></ui-switch>
</section>
<section class="fit-top fit-bottom">
<ui-input v-model="localDriveCapacityMb" type="number">{{ $t('local-drive-capacity-mb') }}<template #suffix>MB</template><template #desc>{{ $t('mb') }}</template></ui-input>
<ui-input v-model="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">{{ $t('remote-drive-capacity-mb') }}<template #suffix>MB</template><template #desc>{{ $t('mb') }}</template></ui-input>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faThumbtack"/> {{ $t('pinned-users') }}</template>
<section class="fit-top">
<ui-textarea v-model="pinnedUsers">
<template #desc>{{ $t('pinned-users-info') }}</template>
</ui-textarea>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faGhost"/> {{ $t('proxy-account-config') }}</template>
<section>
<ui-info>{{ $t('proxy-account-info') }}</ui-info>
<ui-input v-model="proxyAccount"><template #prefix>@</template>{{ $t('proxy-account-username') }}<template #desc>{{ $t('proxy-account-username-desc') }}</template></ui-input>
<ui-info warn>{{ $t('proxy-account-warn') }}</ui-info>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="farEnvelope"/> {{ $t('email-config') }}</template>
<section>
<ui-switch v-model="enableEmail">{{ $t('enable-email') }}<template #desc>{{ $t('email-config-info') }}</template></ui-switch>
<template v-if="enableEmail">
<ui-input v-model="email" type="email" :disabled="!enableEmail">{{ $t('email') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="smtpHost" :disabled="!enableEmail">{{ $t('smtp-host') }}</ui-input>
<ui-input v-model="smtpPort" type="number" :disabled="!enableEmail">{{ $t('smtp-port') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="smtpAuth">{{ $t('smtp-auth') }}</ui-switch>
<ui-horizon-group inputs>
<ui-input v-model="smtpUser" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-user') }}</ui-input>
<ui-input v-model="smtpPass" type="password" :with-password-toggle="true" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-pass') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<template #desc>{{ $t('smtp-secure-info') }}</template></ui-switch>
<ui-button @click="testEmail()">{{ $t('test-email') }}</ui-button>
</template>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faBolt"/> {{ $t('serviceworker-config') }}</template>
<section>
<ui-switch v-model="enableServiceWorker">{{ $t('enable-serviceworker') }}<template #desc>{{ $t('serviceworker-info') }}</template></ui-switch>
<template v-if="enableServiceWorker">
<ui-info>{{ $t('vapid-info') }}<br><code>npm i web-push -g<br>web-push generate-vapid-keys</code></ui-info>
<ui-horizon-group inputs class="fit-bottom">
<ui-input v-model="swPublicKey" :disabled="!enableServiceWorker"><template #icon><fa icon="key"/></template>{{ $t('vapid-publickey') }}</ui-input>
<ui-input v-model="swPrivateKey" :disabled="!enableServiceWorker"><template #icon><fa icon="key"/></template>{{ $t('vapid-privatekey') }}</ui-input>
</ui-horizon-group>
</template>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faShieldAlt"/> {{ $t('recaptcha-config') }}</template>
<section :class="enableRecaptcha ? 'fit-bottom' : ''">
<ui-switch v-model="enableRecaptcha">{{ $t('enable-recaptcha') }}</ui-switch>
<template v-if="enableRecaptcha">
<ui-info>{{ $t('recaptcha-info') }}</ui-info>
<ui-info warn>{{ $t('recaptcha-info2') }}</ui-info>
<ui-horizon-group inputs>
<ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><template #icon><fa icon="key"/></template>{{ $t('recaptcha-site-key') }}</ui-input>
<ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><template #icon><fa icon="key"/></template>{{ $t('recaptcha-secret-key') }}</ui-input>
</ui-horizon-group>
</template>
</section>
<section v-if="enableRecaptcha && recaptchaSiteKey">
<header>{{ $t('recaptcha-preview') }}</header>
<div ref="recaptcha" style="margin: 16px 0 0 0;" :key="recaptchaSiteKey"></div>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faShieldAlt"/> {{ $t('external-service-integration-config') }}</template>
<section>
<header><fa :icon="['fab', 'twitter']"/> {{ $t('twitter-integration-config') }}</header>
<ui-switch v-model="enableTwitterIntegration">{{ $t('enable-twitter-integration') }}</ui-switch>
<template v-if="enableTwitterIntegration">
<ui-horizon-group>
<ui-input v-model="twitterConsumerKey" :disabled="!enableTwitterIntegration"><template #icon><fa icon="key"/></template>{{ $t('twitter-integration-consumer-key') }}</ui-input>
<ui-input v-model="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><template #icon><fa icon="key"/></template>{{ $t('twitter-integration-consumer-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('twitter-integration-info', { url: `${url}/api/tw/cb` }) }}</ui-info>
</template>
</section>
<section>
<header><fa :icon="['fab', 'github']"/> {{ $t('github-integration-config') }}</header>
<ui-switch v-model="enableGithubIntegration">{{ $t('enable-github-integration') }}</ui-switch>
<template v-if="enableGithubIntegration">
<ui-horizon-group>
<ui-input v-model="githubClientId" :disabled="!enableGithubIntegration"><template #icon><fa icon="key"/></template>{{ $t('github-integration-client-id') }}</ui-input>
<ui-input v-model="githubClientSecret" :disabled="!enableGithubIntegration"><template #icon><fa icon="key"/></template>{{ $t('github-integration-client-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('github-integration-info', { url: `${url}/api/gh/cb` }) }}</ui-info>
</template>
</section>
<section>
<header><fa :icon="['fab', 'discord']"/> {{ $t('discord-integration-config') }}</header>
<ui-switch v-model="enableDiscordIntegration">{{ $t('enable-discord-integration') }}</ui-switch>
<template v-if="enableDiscordIntegration">
<ui-horizon-group>
<ui-input v-model="discordClientId" :disabled="!enableDiscordIntegration"><template #icon><fa icon="key"/></template>{{ $t('discord-integration-client-id') }}</ui-input>
<ui-input v-model="discordClientSecret" :disabled="!enableDiscordIntegration"><template #icon><fa icon="key"/></template>{{ $t('discord-integration-client-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('discord-integration-info', { url: `${url}/api/dc/cb` }) }}</ui-info>
</template>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<details>
<summary style="color:var(--text);">{{ $t('advanced-config') }}</summary>
<ui-card>
<template #title><fa :icon="faHashtag"/> {{ $t('hidden-tags') }}</template>
<section class="fit-top">
<ui-textarea v-model="hiddenTags">
<template #desc>{{ $t('hidden-tags-info') }}</template>
</ui-textarea>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title>summaly Proxy</template>
<section class="fit-top fit-bottom">
<ui-input v-model="summalyProxy">URL</ui-input>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
</details>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { url, host } from '../../config';
import { toUnicode } from 'punycode';
import { faHeadset, faShieldAlt, faGhost, faUserPlus, faBolt, faThumbtack, faPencilAlt, faHashtag } from '@fortawesome/free-solid-svg-icons';
import { faEnvelope as farEnvelope, faSave } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/instance.vue'),
data() {
return {
url,
host: toUnicode(host),
maintainerName: null,
maintainerEmail: null,
ToSUrl: null,
repositoryUrl: "https://github.com/syuilo/misskey",
feedbackUrl: null,
disableRegistration: false,
disableLocalTimeline: false,
disableGlobalTimeline: false,
enableEmojiReaction: true,
useStarForReactionFallback: false,
mascotImageUrl: null,
bannerUrl: null,
errorImageUrl: null,
iconUrl: null,
name: null,
description: null,
languages: null,
cacheRemoteFiles: false,
localDriveCapacityMb: null,
remoteDriveCapacityMb: null,
maxNoteTextLength: null,
enableRecaptcha: false,
recaptchaSiteKey: null,
recaptchaSecretKey: null,
enableTwitterIntegration: false,
twitterConsumerKey: null,
twitterConsumerSecret: null,
enableGithubIntegration: false,
githubClientId: null,
githubClientSecret: null,
enableDiscordIntegration: false,
discordClientId: null,
discordClientSecret: null,
proxyAccount: null,
summalyProxy: null,
enableEmail: false,
email: null,
smtpSecure: false,
smtpHost: null,
smtpPort: null,
smtpUser: null,
smtpPass: null,
smtpAuth: false,
enableServiceWorker: false,
swPublicKey: null,
swPrivateKey: null,
pinnedUsers: '',
hiddenTags: '',
useObjectStorage: false,
objectStorageBaseUrl: null,
objectStorageBucket: null,
objectStoragePrefix: null,
objectStorageEndpoint: null,
objectStorageRegion: null,
objectStoragePort: null,
objectStorageAccessKey: null,
objectStorageSecretKey: null,
objectStorageUseSSL: false,
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope, faBolt, faThumbtack, faPencilAlt, faSave, faHashtag
};
},
created() {
this.$root.getMeta(true).then(meta => {
this.maintainerName = meta.maintainerName;
this.maintainerEmail = meta.maintainerEmail;
this.ToSUrl = meta.ToSUrl;
this.repositoryUrl = meta.repositoryUrl;
this.feedbackUrl = meta.feedbackUrl;
this.disableRegistration = meta.disableRegistration;
this.disableLocalTimeline = meta.disableLocalTimeline;
this.disableGlobalTimeline = meta.disableGlobalTimeline;
this.enableEmojiReaction = meta.enableEmojiReaction;
this.useStarForReactionFallback = meta.useStarForReactionFallback;
this.mascotImageUrl = meta.mascotImageUrl;
this.bannerUrl = meta.bannerUrl;
this.errorImageUrl = meta.errorImageUrl;
this.iconUrl = meta.iconUrl;
this.name = meta.name;
this.description = meta.description;
this.languages = meta.langs.join(' ');
this.cacheRemoteFiles = meta.cacheRemoteFiles;
this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
this.maxNoteTextLength = meta.maxNoteTextLength;
this.enableRecaptcha = meta.enableRecaptcha;
this.recaptchaSiteKey = meta.recaptchaSiteKey;
this.recaptchaSecretKey = meta.recaptchaSecretKey;
this.proxyAccount = meta.proxyAccount;
this.enableTwitterIntegration = meta.enableTwitterIntegration;
this.twitterConsumerKey = meta.twitterConsumerKey;
this.twitterConsumerSecret = meta.twitterConsumerSecret;
this.enableGithubIntegration = meta.enableGithubIntegration;
this.githubClientId = meta.githubClientId;
this.githubClientSecret = meta.githubClientSecret;
this.enableDiscordIntegration = meta.enableDiscordIntegration;
this.discordClientId = meta.discordClientId;
this.discordClientSecret = meta.discordClientSecret;
this.summalyProxy = meta.summalyProxy;
this.enableEmail = meta.enableEmail;
this.email = meta.email;
this.smtpSecure = meta.smtpSecure;
this.smtpHost = meta.smtpHost;
this.smtpPort = meta.smtpPort;
this.smtpUser = meta.smtpUser;
this.smtpPass = meta.smtpPass;
this.smtpAuth = meta.smtpUser != null && meta.smtpUser !== '';
this.enableServiceWorker = meta.enableServiceWorker;
this.swPublicKey = meta.swPublickey;
this.swPrivateKey = meta.swPrivateKey;
this.pinnedUsers = meta.pinnedUsers.join('\n');
this.hiddenTags = meta.hiddenTags.join('\n');
this.useObjectStorage = meta.useObjectStorage;
this.objectStorageBaseUrl = meta.objectStorageBaseUrl;
this.objectStorageBucket = meta.objectStorageBucket;
this.objectStoragePrefix = meta.objectStoragePrefix;
this.objectStorageEndpoint = meta.objectStorageEndpoint;
this.objectStorageRegion = meta.objectStorageRegion;
this.objectStoragePort = meta.objectStoragePort;
this.objectStorageAccessKey = meta.objectStorageAccessKey;
this.objectStorageSecretKey = meta.objectStorageSecretKey;
this.objectStorageUseSSL = meta.objectStorageUseSSL;
});
},
mounted() {
const renderRecaptchaPreview = () => {
if (!(window as any).grecaptcha) return;
if (!this.$refs.recaptcha) return;
if (!this.recaptchaSiteKey) return;
(window as any).grecaptcha.render(this.$refs.recaptcha, {
sitekey: this.recaptchaSiteKey
});
};
window.onRecaotchaLoad = () => {
renderRecaptchaPreview();
};
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js?onload=onRecaotchaLoad');
head.appendChild(script);
this.$watch('enableRecaptcha', () => {
renderRecaptchaPreview();
});
this.$watch('recaptchaSiteKey', () => {
renderRecaptchaPreview();
});
},
methods: {
invite() {
this.$root.api('admin/invite').then(x => {
this.$root.dialog({
type: 'info',
text: x.code
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
},
async testEmail() {
this.$root.api('admin/send-email', {
to: this.maintainerEmail,
subject: 'Test email',
text: 'Yo'
}).then(x => {
this.$root.dialog({
type: 'success',
splash: true
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
},
updateMeta() {
this.$root.api('admin/update-meta', {
maintainerName: this.maintainerName,
maintainerEmail: this.maintainerEmail,
ToSUrl: this.ToSUrl,
repositoryUrl: this.repositoryUrl,
feedbackUrl: this.feedbackUrl,
disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline,
disableGlobalTimeline: this.disableGlobalTimeline,
enableEmojiReaction: this.enableEmojiReaction,
useStarForReactionFallback: this.useStarForReactionFallback,
mascotImageUrl: this.mascotImageUrl,
bannerUrl: this.bannerUrl,
errorImageUrl: this.errorImageUrl,
iconUrl: this.iconUrl,
name: this.name,
description: this.description,
langs: this.languages ? this.languages.split(' ') : [],
cacheRemoteFiles: this.cacheRemoteFiles,
localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
maxNoteTextLength: parseInt(this.maxNoteTextLength, 10),
enableRecaptcha: this.enableRecaptcha,
recaptchaSiteKey: this.recaptchaSiteKey,
recaptchaSecretKey: this.recaptchaSecretKey,
proxyAccount: this.proxyAccount,
enableTwitterIntegration: this.enableTwitterIntegration,
twitterConsumerKey: this.twitterConsumerKey,
twitterConsumerSecret: this.twitterConsumerSecret,
enableGithubIntegration: this.enableGithubIntegration,
githubClientId: this.githubClientId,
githubClientSecret: this.githubClientSecret,
enableDiscordIntegration: this.enableDiscordIntegration,
discordClientId: this.discordClientId,
discordClientSecret: this.discordClientSecret,
summalyProxy: this.summalyProxy,
enableEmail: this.enableEmail,
email: this.email,
smtpSecure: this.smtpSecure,
smtpHost: this.smtpHost,
smtpPort: parseInt(this.smtpPort, 10),
smtpUser: this.smtpAuth ? this.smtpUser : '',
smtpPass: this.smtpAuth ? this.smtpPass : '',
enableServiceWorker: this.enableServiceWorker,
swPublicKey: this.swPublicKey,
swPrivateKey: this.swPrivateKey,
pinnedUsers: this.pinnedUsers ? this.pinnedUsers.split('\n') : [],
hiddenTags: this.hiddenTags ? this.hiddenTags.split('\n') : [],
useObjectStorage: this.useObjectStorage,
objectStorageBaseUrl: this.objectStorageBaseUrl ? this.objectStorageBaseUrl : null,
objectStorageBucket: this.objectStorageBucket ? this.objectStorageBucket : null,
objectStoragePrefix: this.objectStoragePrefix ? this.objectStoragePrefix : null,
objectStorageEndpoint: this.objectStorageEndpoint ? this.objectStorageEndpoint : null,
objectStorageRegion: this.objectStorageRegion ? this.objectStorageRegion : null,
objectStoragePort: this.objectStoragePort ? this.objectStoragePort : null,
objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
objectStorageUseSSL: this.objectStorageUseSSL,
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('saved')
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
}
}
});
</script>

View File

@ -1,119 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faStream"/> {{ $t('logs') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-input v-model="domain" :debounce="true">
<span>{{ $t('domain') }}</span>
</ui-input>
<ui-select v-model="level">
<template #label>{{ $t('level') }}</template>
<option value="all">{{ $t('levels.all') }}</option>
<option value="info">{{ $t('levels.info') }}</option>
<option value="success">{{ $t('levels.success') }}</option>
<option value="warning">{{ $t('levels.warning') }}</option>
<option value="error">{{ $t('levels.error') }}</option>
<option value="debug">{{ $t('levels.debug') }}</option>
</ui-select>
</ui-horizon-group>
<div class="nqjzuvev">
<code v-for="log in logs" :key="log.id" :class="log.level">
<details>
<summary><mk-time :time="log.createdAt"/> [{{ log.domain.join('.') }}] {{ log.message }}</summary>
<vue-json-pretty v-if="log.data" :data="log.data"></vue-json-pretty>
</details>
</code>
</div>
<ui-button @click="deleteAll()">{{ $t('delete-all') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faStream } from '@fortawesome/free-solid-svg-icons';
import VueJsonPretty from 'vue-json-pretty';
export default Vue.extend({
i18n: i18n('admin/views/logs.vue'),
components: {
VueJsonPretty
},
data() {
return {
logs: [],
level: 'all',
domain: '',
faStream
};
},
watch: {
level() {
this.logs = [];
this.fetch();
},
domain() {
this.logs = [];
this.fetch();
}
},
mounted() {
this.fetch();
},
methods: {
fetch() {
this.$root.api('admin/logs', {
level: this.level === 'all' ? null : this.level,
domain: this.domain === '' ? null : this.domain,
limit: 100
}).then(logs => {
this.logs = logs.reverse();
});
},
deleteAll() {
this.$root.api('admin/delete-logs').then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
});
}
}
});
</script>
<style lang="stylus" scoped>
.nqjzuvev
padding 8px
background #000
color #fff
font-size 14px
> code
display block
&.error
color #f00
&.warning
color #ff0
&.success
color #0f0
&.debug
opacity 0.7
</style>

View File

@ -1,127 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa icon="plus"/> {{ $t('add-moderator.title') }}</template>
<section class="fit-top">
<ui-input v-model="username" type="text">
<template #prefix>@</template>
</ui-input>
<ui-horizon-group>
<ui-button @click="add" :disabled="changing">{{ $t('add-moderator.add') }}</ui-button>
<ui-button @click="remove" :disabled="changing">{{ $t('add-moderator.remove') }}</ui-button>
</ui-horizon-group>
</section>
</ui-card>
<ui-card>
<template #title>{{ $t('logs.title') }}</template>
<section class="fit-top">
<sequential-entrance animation="entranceFromTop" delay="25">
<div v-for="log in logs" :key="log.id" class="">
<ui-horizon-group inputs>
<ui-input :value="log.user | acct" type="text" readonly>
<span>{{ $t('logs.moderator') }}</span>
</ui-input>
<ui-input :value="log.type" type="text" readonly>
<span>{{ $t('logs.type') }}</span>
</ui-input>
<ui-input :value="log.createdAt | date" type="text" readonly>
<span>{{ $t('logs.at') }}</span>
</ui-input>
</ui-horizon-group>
<ui-textarea :value="JSON.stringify(log.info, null, 4)" readonly>
<span>{{ $t('logs.info') }}</span>
</ui-textarea>
</div>
</sequential-entrance>
<ui-button v-if="existMoreLogs" @click="fetchLogs">{{ $t('@.load-more') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse";
export default Vue.extend({
i18n: i18n('admin/views/moderators.vue'),
data() {
return {
username: '',
changing: false,
logs: [],
untilLogId: null,
existMoreLogs: false
};
},
created() {
this.fetchLogs();
},
methods: {
async add() {
this.changing = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.username));
await this.$root.api('admin/moderators/add', { userId: user.id });
this.$root.dialog({
type: 'success',
text: this.$t('add-moderator.added')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.changing = false;
},
async remove() {
this.changing = true;
const process = async () => {
const user = await this.$root.api('users/show', parseAcct(this.username));
await this.$root.api('admin/moderators/remove', { userId: user.id });
this.$root.dialog({
type: 'success',
text: this.$t('add-moderator.removed')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.changing = false;
},
fetchLogs() {
this.$root.api('admin/show-moderation-logs', {
untilId: this.untilId,
limit: 10 + 1
}).then(logs => {
if (logs.length == 10 + 1) {
logs.pop();
this.existMoreLogs = true;
} else {
this.existMoreLogs = false;
}
this.logs = this.logs.concat(logs);
this.untilLogId = this.logs[this.logs.length - 1].id;
});
},
}
});
</script>

View File

@ -1,181 +0,0 @@
<template>
<div>
<ui-info warn v-if="latestStats && latestStats.waiting > 0">The queue is jammed.</ui-info>
<ui-horizon-group inputs v-if="latestStats" class="fit-bottom">
<ui-input :value="latestStats.activeSincePrevTick | number" type="text" readonly>
<span>Process</span>
<template #prefix><fa :icon="fasPlayCircle"/></template>
<template #suffix>jobs/tick</template>
</ui-input>
<ui-input :value="latestStats.active | number" type="text" readonly>
<span>Active</span>
<template #prefix><fa :icon="farPlayCircle"/></template>
<template #suffix>jobs</template>
</ui-input>
<ui-input :value="latestStats.waiting | number" type="text" readonly>
<span>Waiting</span>
<template #prefix><fa :icon="faStopCircle"/></template>
<template #suffix>jobs</template>
</ui-input>
<ui-input :value="latestStats.delayed | number" type="text" readonly>
<span>Delayed</span>
<template #prefix><fa :icon="faStopwatch"/></template>
<template #suffix>jobs</template>
</ui-input>
</ui-horizon-group>
<div ref="chart" class="wptihjuy"></div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import ApexCharts from 'apexcharts';
import * as tinycolor from 'tinycolor2';
import { faStopwatch, faPlayCircle as fasPlayCircle } from '@fortawesome/free-solid-svg-icons';
import { faStopCircle, faPlayCircle as farPlayCircle } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/queue.vue'),
props: {
type: {
type: String,
required: true
},
connection: {
required: true
},
limit: {
type: Number,
required: true
}
},
data() {
return {
stats: [],
chart: null,
faStopwatch, faStopCircle, farPlayCircle, fasPlayCircle
};
},
computed: {
latestStats(): any {
return this.stats.length > 0 ? this.stats[this.stats.length - 1][this.type] : null;
}
},
watch: {
stats(stats) {
this.chart.updateSeries([{
name: 'Process',
type: 'area',
data: stats.map((x, i) => ({ x: i, y: x[this.type].activeSincePrevTick }))
}, {
name: 'Active',
type: 'area',
data: stats.map((x, i) => ({ x: i, y: x[this.type].active }))
}, {
name: 'Waiting',
type: 'line',
data: stats.map((x, i) => ({ x: i, y: x[this.type].waiting }))
}, {
name: 'Delayed',
type: 'line',
data: stats.map((x, i) => ({ x: i, y: x[this.type].delayed }))
}]);
},
},
mounted() {
this.chart = new ApexCharts(this.$refs.chart, {
chart: {
id: this.type,
group: 'queue',
type: 'area',
height: 200,
animations: {
dynamicAnimation: {
enabled: false
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)',
xaxis: {
lines: {
show: true,
}
},
},
stroke: {
curve: 'straight',
width: 2
},
tooltip: {
enabled: false
},
legend: {
labels: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
},
},
series: [] as any,
colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'],
xaxis: {
type: 'numeric',
labels: {
show: false
},
tooltip: {
enabled: false
}
},
yaxis: {
show: false,
min: 0,
}
});
this.chart.render();
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.$once('hook:beforeDestroy', () => {
if (this.chart) this.chart.destroy();
});
},
methods: {
onStats(stats) {
this.stats.push(stats);
if (this.stats.length > this.limit) this.stats.shift();
},
onStatsLog(statsLog) {
for (const stats of statsLog.reverse()) {
this.onStats(stats);
}
},
}
});
</script>
<style lang="stylus" scoped>
.wptihjuy
min-height 200px !important
margin -8px
</style>

View File

@ -1,155 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faChartBar"/> {{ $t('title') }}</template>
<section>
<header><fa :icon="faPaperPlane"/> {{ $t('domains.deliver') }}</header>
<x-chart v-if="connection" :connection="connection" :limit="chartLimit" type="deliver"/>
</section>
<section>
<header><fa :icon="faInbox"/> {{ $t('domains.inbox') }}</header>
<x-chart v-if="connection" :connection="connection" :limit="chartLimit" type="inbox"/>
</section>
<section>
<details>
<summary>{{ $t('other-queues') }}</summary>
<section>
<header><fa :icon="faDatabase"/> {{ $t('domains.db') }}</header>
<x-chart v-if="connection" :connection="connection" :limit="chartLimit" type="db"/>
</section>
<ui-hr/>
<section>
<header><fa :icon="faCloud"/> {{ $t('domains.objectStorage') }}</header>
<x-chart v-if="connection" :connection="connection" :limit="chartLimit" type="objectStorage"/>
</section>
</details>
</section>
<section>
<ui-button @click="removeAllJobs">{{ $t('remove-all-jobs') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faTasks"/> {{ $t('jobs') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-select v-model="domain">
<template #label>{{ $t('queue') }}</template>
<option value="deliver">{{ $t('domains.deliver') }}</option>
<option value="inbox">{{ $t('domains.inbox') }}</option>
<option value="db">{{ $t('domains.db') }}</option>
<option value="objectStorage">{{ $t('domains.objectStorage') }}</option>
</ui-select>
<ui-select v-model="state">
<template #label>{{ $t('state') }}</template>
<option value="active">{{ $t('states.active') }}</option>
<option value="waiting">{{ $t('states.waiting') }}</option>
<option value="delayed">{{ $t('states.delayed') }}</option>
</ui-select>
</ui-horizon-group>
<sequential-entrance animation="entranceFromTop" delay="25">
<div class="xvvuvgsv" v-for="job in jobs">
<b>{{ job.id }}</b>
<template v-if="domain === 'deliver'">
<span>{{ job.data.to }}</span>
</template>
<template v-if="domain === 'inbox'">
<span>{{ job.activity.id }}</span>
</template>
</div>
</sequential-entrance>
<ui-info v-if="jobs.length == jobsLimit">{{ $t('result-is-truncated', { n: jobsLimit }) }}</ui-info>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { faTasks, faInbox, faDatabase, faCloud } from '@fortawesome/free-solid-svg-icons';
import { faPaperPlane, faChartBar } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../i18n';
import XChart from './queue.chart.vue';
export default Vue.extend({
i18n: i18n('admin/views/queue.vue'),
components: {
XChart
},
data() {
return {
connection: null,
chartLimit: 200,
jobs: [],
jobsLimit: 50,
domain: 'deliver',
state: 'delayed',
faTasks, faPaperPlane, faInbox, faChartBar, faDatabase, faCloud
};
},
watch: {
domain() {
this.jobs = [];
this.fetchJobs();
},
state() {
this.jobs = [];
this.fetchJobs();
},
},
mounted() {
this.fetchJobs();
this.connection = this.$root.stream.useSharedConnection('queueStats');
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: this.chartLimit
});
this.$once('hook:beforeDestroy', () => {
this.connection.dispose();
});
},
methods: {
async removeAllJobs() {
const process = async () => {
await this.$root.api('admin/queue/clear');
this.$root.dialog({
type: 'success',
splash: true
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
fetchJobs() {
this.$root.api('admin/queue/jobs', {
domain: this.domain,
state: this.state,
limit: this.jobsLimit
}).then(jobs => {
this.jobs = jobs;
});
},
}
});
</script>
<style lang="stylus" scoped>
.xvvuvgsv
> b
margin-right 16px
</style>

View File

@ -1,95 +0,0 @@
<template>
<div class="kofvwchc">
<div>
<a :href="user | userPage(null, true)">
<mk-avatar class="avatar" :user="user" :disable-link="true"/>
</a>
</div>
<div @click="click(user.id)">
<header>
<b><mk-user-name :user="user"/></b>
<span class="username">@{{ user | acct }}</span>
<span class="is-admin" v-if="user.isAdmin">admin</span>
<span class="is-moderator" v-if="user.isModerator">moderator</span>
<span class="is-silenced" v-if="user.isSilenced" :title="$t('@.silenced-user')"><fa :icon="faMicrophoneSlash"/></span>
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
</header>
<div>
<span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span>
</div>
<div>
<span>{{ $t('users.createdAt') }}: <mk-time :time="user.createdAt" mode="detail"/></span>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/users.vue'),
props: ['user', 'click'],
data() {
return {
faSnowflake, faMicrophoneSlash
};
},
});
</script>
<style lang="stylus" scoped>
.kofvwchc
display flex
padding 16px
border-top solid 1px var(--faceDivider)
> div:first-child
> a
> .avatar
width 64px
height 64px
> div:last-child
flex 1
cursor pointer
padding-left 16px
@media (max-width 500px)
font-size 14px
> header
> .username
margin-left 8px
opacity 0.7
> .is-admin
> .is-moderator
flex-shrink 0
align-self center
margin 0 0 0 .5em
padding 1px 6px
font-size 80%
border-radius 3px
background var(--noteHeaderAdminBg)
color var(--noteHeaderAdminFg)
> .is-silenced
> .is-suspended
margin 0 0 0 .5em
color #4dabf7
&:hover
color var(--primaryForeground)
background var(--primary)
text-decoration none
border-radius 3px
&:active
color var(--primaryForeground)
background var(--primaryDarken10)
border-radius 3px
</style>

View File

@ -1,366 +0,0 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faTerminal"/> {{ $t('operation') }}</template>
<section class="fit-top">
<ui-input class="target" v-model="target" type="text" @enter="showUser">
<span>{{ $t('username-or-userid') }}</span>
</ui-input>
<ui-button @click="showUser"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
<div ref="user" class="user" v-if="user" :key="user.id">
<x-user :user="user"/>
<div class="actions">
<ui-button v-if="user.host != null" @click="updateRemoteUser"><fa :icon="faSync"/> {{ $t('update-remote-user') }}</ui-button>
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
<ui-horizon-group>
<ui-button @click="silenceUser"><fa :icon="faMicrophoneSlash"/> {{ $t('make-silence') }}</ui-button>
<ui-button @click="unsilenceUser">{{ $t('unmake-silence') }}</ui-button>
</ui-horizon-group>
<ui-horizon-group>
<ui-button @click="suspendUser" :disabled="suspending"><fa :icon="faSnowflake"/> {{ $t('suspend') }}</ui-button>
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
</ui-horizon-group>
<ui-button @click="deleteAllFiles"><fa :icon="faTrashAlt"/> {{ $t('delete-all-files') }}</ui-button>
<ui-textarea v-if="user" :value="user | json5" readonly tall style="margin-top:16px;"></ui-textarea>
</div>
</div>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faUsers"/> {{ $t('users.title') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-select v-model="sort">
<template #label>{{ $t('users.sort.title') }}</template>
<option value="-createdAt">{{ $t('users.sort.createdAtAsc') }}</option>
<option value="+createdAt">{{ $t('users.sort.createdAtDesc') }}</option>
<option value="-updatedAt">{{ $t('users.sort.updatedAtAsc') }}</option>
<option value="+updatedAt">{{ $t('users.sort.updatedAtDesc') }}</option>
</ui-select>
<ui-select v-model="state">
<template #label>{{ $t('users.state.title') }}</template>
<option value="all">{{ $t('users.state.all') }}</option>
<option value="available">{{ $t('users.state.available') }}</option>
<option value="admin">{{ $t('users.state.admin') }}</option>
<option value="moderator">{{ $t('users.state.moderator') }}</option>
<option value="silenced">{{ $t('users.state.silenced') }}</option>
<option value="suspended">{{ $t('users.state.suspended') }}</option>
</ui-select>
<ui-select v-model="origin">
<template #label>{{ $t('users.origin.title') }}</template>
<option value="combined">{{ $t('users.origin.combined') }}</option>
<option value="local">{{ $t('users.origin.local') }}</option>
<option value="remote">{{ $t('users.origin.remote') }}</option>
</ui-select>
</ui-horizon-group>
<ui-horizon-group searchboxes>
<ui-input v-model="searchUsername" type="text" spellcheck="false" @input="fetchUsers(true)">
<span>{{ $t('username') }}</span>
</ui-input>
<ui-input v-model="searchHost" type="text" spellcheck="false" @input="fetchUsers(true)" :disabled="origin === 'local'">
<span>{{ $t('host') }}</span>
</ui-input>
</ui-horizon-group>
<sequential-entrance animation="entranceFromTop" delay="25">
<x-user v-for="user in users" :key="user.id" :user='user' :click="showUserOnClick"/>
</sequential-entrance>
<ui-button v-if="existMore" @click="fetchUsers">{{ $t('@.load-more') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse";
import { faUsers, faTerminal, faSearch, faKey, faSync, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
import XUser from './users.user.vue';
export default Vue.extend({
i18n: i18n('admin/views/users.vue'),
components: {
XUser
},
data() {
return {
user: null,
target: null,
suspending: false,
unsuspending: false,
sort: '+createdAt',
state: 'all',
origin: 'local',
searchUsername: '',
searchHost: '',
limit: 10,
offset: 0,
users: [],
existMore: false,
faTerminal, faUsers, faSnowflake, faSearch, faKey, faSync, faMicrophoneSlash, faTrashAlt
};
},
watch: {
sort() {
this.users = [];
this.offset = 0;
this.fetchUsers();
},
state() {
this.users = [];
this.offset = 0;
this.fetchUsers();
},
origin() {
if (this.origin === 'local') this.searchHost = '';
this.users = [];
this.offset = 0;
this.fetchUsers();
}
},
mounted() {
this.fetchUsers();
},
methods: {
/** テキストエリアのユーザーを解決する */
fetchUser() {
return new Promise((res) => {
const usernamePromise = this.$root.api('users/show', parseAcct(this.target));
const idPromise = this.$root.api('users/show', { userId: this.target });
let _notFound = false;
const notFound = () => {
if (_notFound) {
this.$root.dialog({
type: 'error',
text: this.$t('user-not-found')
});
} else {
_notFound = true;
}
};
usernamePromise.then(res).catch(e => {
if (e == 'user not found') {
notFound();
}
});
idPromise.then(res).catch(e => {
notFound();
});
});
},
/** テキストエリアから処理対象ユーザーを設定する */
async showUser() {
this.user = null;
const user = await this.fetchUser();
this.$root.api('admin/show-user', { userId: user.id }).then(info => {
this.user = info;
});
this.target = '';
},
async showUserOnClick(userId: string) {
this.$root.api('admin/show-user', { userId: userId }).then(info => {
this.user = info;
this.$nextTick(() => {
this.$refs.user.scrollIntoView();
});
});
},
/** 処理対象ユーザーの情報を更新する */
async refreshUser() {
this.$root.api('admin/show-user', { userId: this.user.id }).then(info => {
this.user = info;
});
},
async resetPassword() {
if (!await this.getConfirmed(this.$t('reset-password-confirm'))) return;
this.$root.api('admin/reset-password', { userId: this.user.id }).then(res => {
this.$root.dialog({
type: 'success',
text: this.$t('password-updated', { password: res.password })
});
});
},
async silenceUser() {
if (!await this.getConfirmed(this.$t('silence-confirm'))) return;
const process = async () => {
await this.$root.api('admin/silence-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
splash: true
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.refreshUser();
},
async unsilenceUser() {
if (!await this.getConfirmed(this.$t('unsilence-confirm'))) return;
const process = async () => {
await this.$root.api('admin/unsilence-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
splash: true
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.refreshUser();
},
async suspendUser() {
if (!await this.getConfirmed(this.$t('suspend-confirm'))) return;
this.suspending = true;
const process = async () => {
await this.$root.api('admin/suspend-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
text: this.$t('suspended')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.suspending = false;
this.refreshUser();
},
async unsuspendUser() {
if (!await this.getConfirmed(this.$t('unsuspend-confirm'))) return;
this.unsuspending = true;
const process = async () => {
await this.$root.api('admin/unsuspend-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
text: this.$t('unsuspended')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.unsuspending = false;
this.refreshUser();
},
async updateRemoteUser() {
this.$root.api('admin/update-remote-user', { userId: this.user.id }).then(res => {
this.$root.dialog({
type: 'success',
text: this.$t('remote-user-updated')
});
});
this.refreshUser();
},
async deleteAllFiles() {
if (!await this.getConfirmed(this.$t('delete-all-files-confirm'))) return;
const process = async () => {
await this.$root.api('admin/delete-all-files-of-a-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
splash: true
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
async getConfirmed(text: string): Promise<Boolean> {
const confirm = await this.$root.dialog({
type: 'warning',
showCancelButton: true,
title: 'confirm',
text,
});
return !confirm.canceled;
},
fetchUsers(truncate?: boolean) {
if (truncate) this.offset = 0;
this.$root.api('admin/show-users', {
state: this.state,
origin: this.origin,
sort: this.sort,
offset: this.offset,
limit: this.limit + 1,
username: this.searchUsername,
hostname: this.searchHost
}).then(users => {
if (users.length == this.limit + 1) {
users.pop();
this.existMore = true;
} else {
this.existMore = false;
}
this.users = truncate ? users : this.users.concat(users);
this.offset += this.limit;
});
}
}
});
</script>
<style lang="stylus" scoped>
.target
margin-bottom 16px !important
.user
margin-top 32px
> .actions
margin-left 80px
</style>

View File

@ -1,47 +0,0 @@
.zoom-in-top-enter-active,
.zoom-in-top-leave-active {
opacity: 1;
transform: scaleY(1);
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
transform-origin: center top;
}
.zoom-in-top-enter,
.zoom-in-top-leave-active {
opacity: 0;
transform: scaleY(0);
}
.entranceFromTop {
animation-duration: 0.5s;
animation-name: entranceFromTop;
}
@keyframes entranceFromTop {
from {
opacity: 0;
transform: translateY(-64px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes jump {
0% { transform: translateY(0); }
25% { transform: translateY(-16px); }
50% { transform: translateY(0); }
75% { transform: translateY(-8px); }
100% { transform: translateY(0); }
}
@keyframes blink {
0% { opacity: 1; }
30% { opacity: 1; }
90% { opacity: 0; }
}

Some files were not shown because too many files have changed in this diff Show More