Compare commits

...

172 Commits

Author SHA1 Message Date
syuilo
41d041f701 Merge branch 'develop' 2019-07-09 17:03:38 +09:00
syuilo
3e516474c2 11.25.1 2019-07-09 17:03:24 +09:00
syuilo
405c9c258b New translations ja-JP.yml (English) (#5126) 2019-07-09 17:01:28 +09:00
MeiMei
24e389bcf3 Tune font (#5125) 2019-07-09 17:01:08 +09:00
syuilo
933c83679e Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-07-09 16:55:59 +09:00
syuilo
a7aa924949 Add userId prop 2019-07-09 16:55:55 +09:00
syuilo
0eb84fe874 Fix bug 2019-07-09 16:55:33 +09:00
syuilo
2f451fa058 New translations ja-JP.yml (English) (#5123) 2019-07-09 09:53:24 +09:00
syuilo
2465a377a1 Delete init.ts 2019-07-09 04:09:02 +09:00
syuilo
697219e946 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-07-09 00:11:18 +09:00
syuilo
4478298a0a Update uodate docs 2019-07-09 00:11:04 +09:00
syuilo
925f89720a New translations ja-JP.yml (Korean) (#5121) 2019-07-08 17:02:58 +09:00
syuilo
0f71d9f47a Merge branch 'develop' 2019-07-08 16:17:47 +09:00
syuilo
a7ec54ea97 11.25.0 2019-07-08 16:17:14 +09:00
syuilo
1d43d18b19 🎨 2019-07-08 16:11:52 +09:00
syuilo
0bcb25a983 New Crowdin translations (#5102)
* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Czech)

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

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Czech)

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

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Czech)

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

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Spanish)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Czech)

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

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (Spanish)

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

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

* New translations ja-JP.yml (English)
2019-07-08 16:04:24 +09:00
syuilo
ec1f2a285b Resolve #5116 2019-07-08 16:03:17 +09:00
Satsuki Yanagi
c2c06694da Allow only one kind of date identifier at once (#5120) 2019-07-08 13:55:22 +09:00
tamaina
5343b005df Improve paste uploading Resolve #3023 (#4542)
* resolve #3023

* fix

* fix

* better description

* widget

* fix text

* Update post-form.vue

* Fix enter-file-name dialog title text

* Fix type

* On messaging room

* Replace moment.js to original one

* Fix formatDateTimeString
2019-07-08 13:46:31 +09:00
syuilo
eb783f827c Better display in narrow desktop and choosing client type; Fix #1442, Fix #2106, Resolve #4552 (#4549)
* fix #1442, fix #2106

* revert

* wip

* ✌️

* clean up

* fix

* https://github.com/syuilo/misskey/pull/4549#discussion_r287750004
2019-07-08 04:36:06 +09:00
syuilo
6064c3ae47 Add semicolons 2019-07-08 04:32:57 +09:00
syuilo
05862a420f Merge branch 'develop' into pr/4549 2019-07-08 04:27:18 +09:00
syuilo
393ad283e1 🎨 2019-07-08 04:19:17 +09:00
syuilo
841c8d619f 既定のアップロード先フォルダを設定できるように 2019-07-08 04:17:53 +09:00
YuzuRyo61
5c2ed9e5d3 11.24.0の注意書きを追記 (#5108) 2019-07-07 19:00:38 +09:00
MeiMei
d39aabc143 Fix notification wrap (#5118) 2019-07-07 18:59:54 +09:00
Satsuki Yanagi
4628f507e5 公開以外へのリプライ時元の公開範囲で指定したユーザー情報を引き継ぐように (#5119)
* 公開以外へのリプライ時元の公開範囲で指定したユーザー情報を引き継ぐように

* Use users/show userIds
2019-07-07 17:14:08 +09:00
syuilo
8b05816860 Refactor: Remove needless return 2019-07-07 15:29:08 +09:00
Satsuki Yanagi
3b8ea90fdc フォルダーを削除できないときダイアログボックスで知らせる (#5111)
* フォルダーを削除できないときダイアログボックスで知らせる

* https://github.com/syuilo/misskey/pull/5111#issuecomment-508959068

かわいい
2019-07-07 14:56:51 +09:00
MeiMei
638458e2c1 Fix: postgres redis cache の option が適用されない (#5114) 2019-07-07 07:59:59 +09:00
syuilo
bd8d7c3d0f Improve Page
* ページをピン留めできるように
* デッキでカラム内でページを見れるように
2019-07-07 06:56:13 +09:00
syuilo
4b747d20b7 Use npx to avoid global install of ts-node 2019-07-07 05:26:04 +09:00
syuilo
351b236014 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-07-07 05:13:21 +09:00
syuilo
e9251debe0 イベント送信時に指定の変数の値を添付出来るように 2019-07-07 05:12:31 +09:00
tamaina
22c4842154 https://github.com/syuilo/misskey/pull/4549#discussion_r287750004 2019-07-07 02:22:33 +09:00
tamaina
788edd3622 fix 2019-07-07 02:22:33 +09:00
tamaina
5afe96e15a clean up 2019-07-07 02:22:08 +09:00
tamaina
899fc8a7bd ✌️ 2019-07-07 02:22:08 +09:00
tamaina
2afcdda058 wip 2019-07-07 02:21:13 +09:00
tamaina
c2fc637575 revert 2019-07-07 02:18:24 +09:00
tamaina
82d2b0608f fix #1442, fix #2106 2019-07-07 02:18:24 +09:00
Satsuki Yanagi
047a46d966 Support password-less login with WebAuthn (#5112)
* Support password-less login with WebAuthn

* Fix initial value of usePasswordLessLogin
2019-07-07 01:38:36 +09:00
syuilo
e97dd13e81 Pages: ボタンを色付き表示できるように 2019-07-06 23:11:16 +09:00
syuilo
067e9ec6f4 Fix bug 2019-07-06 22:53:15 +09:00
syuilo
64397708fd MisskeyPagesにイベント送信ボタンを追加 2019-07-06 18:14:50 +09:00
syuilo
5ae6b0058f やった (#5110) 2019-07-06 00:46:00 +09:00
syuilo
c201326906 Merge branch 'develop' 2019-07-05 22:36:13 +09:00
syuilo
3bc2fe8527 11.24.2 2019-07-05 22:35:52 +09:00
syuilo
c76c1fc4ef Update CHANGELOG.md 2019-07-05 22:34:34 +09:00
syuilo
fb3fa06ae7 Update CHANGELOG.md 2019-07-05 22:33:54 +09:00
syuilo
48353cccae Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-07-05 22:32:19 +09:00
syuilo
65bf863093 Fix #4760 2019-07-05 22:32:15 +09:00
MeiMei
87a6ef0581 Fix: SingleLineなMFMが折り返されてしまう (#5109) 2019-07-05 21:47:18 +09:00
syuilo
af583d2ef6 Update CHANGELOG.md 2019-07-05 21:21:09 +09:00
syuilo
68d49bc770 Add PB 2019-07-05 21:18:49 +09:00
syuilo
d848195a6e チャートで数字が表示される問題を修正 2019-07-05 21:13:52 +09:00
syuilo
3c5324bbbb Merge branch 'develop' 2019-07-05 18:02:42 +09:00
syuilo
e2d59293fb 11.24.1 2019-07-05 18:02:29 +09:00
MeiMei
411f038f34 Fix: カスタム絵文字リアクションがたまに文字になってしまう (#5105) 2019-07-05 17:58:54 +09:00
MeiMei
26f2ae093b APNGでもMIME typeはimage/pngにするように (#5100)
* APNGでもMIME typeはimage/pngにするように

* Revert "APNGでもMIME typeはimage/pngにするように"

This reverts commit e579eb2bf4.

* APNGはファイル送信時のみimage/pngにするように
2019-07-05 17:44:23 +09:00
Satsuki Yanagi
6a53ccf814 ハッシュタグのトレンドの計算を5分単位で丸める (#5107) 2019-07-05 08:43:56 +09:00
Satsuki Yanagi
114523e69e Fix WebAuthn login (#5103) 2019-07-05 07:48:12 +09:00
Satsuki Yanagi
d5caf22d8c Update Emojis immediately (#5106) 2019-07-05 07:45:00 +09:00
Satsuki Yanagi
a8f945ae8e Update node version (#5101) 2019-07-05 02:48:32 +09:00
syuilo
d078f78602 Merge branch 'develop' 2019-07-05 02:13:02 +09:00
syuilo
a5c6145237 11.24.0 2019-07-05 02:12:45 +09:00
syuilo
50df9f7dff Update node version 2019-07-05 02:12:23 +09:00
syuilo
7b33522d97 New Crowdin translations (#5082)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Polish)

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

* New translations ja-JP.yml (Polish)

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

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Czech)

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

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Korean)
2019-07-05 02:09:59 +09:00
syuilo
d3edf03125 Fix errors 2019-07-05 02:00:54 +09:00
Acid Chicken (硫酸鶏)
d5cd38b459 Create partial type definition for 'jsrsasign' (#5092)
* Create partial type definition for 'jsrsasign'

* Update comments

* Add jsrsasign dependency

* Make some params of Signature class optional

* Make init argument of Signature.init optional
2019-07-05 01:54:16 +09:00
syuilo
2c76d410ab Resolve #1867 2019-07-04 22:59:52 +09:00
syuilo
dfd991a6c6 テストメールは管理者アドレスに送信するように 2019-07-04 21:08:47 +09:00
syuilo
16b81fff38 Resolve #3431 2019-07-04 21:07:02 +09:00
syuilo
f379a721f1 Fix bug 2019-07-04 20:52:21 +09:00
syuilo
194a958d40 Update CHANGELOG.md 2019-07-04 20:40:02 +09:00
syuilo
327ffd3498 Resolve #4321 2019-07-04 20:39:33 +09:00
syuilo
40276d7f1a テストページ廃止 2019-07-04 20:26:12 +09:00
syuilo
9254f95679 Update CHANGELOG.md 2019-07-04 15:14:13 +09:00
syuilo
2e1a9dffbe Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-07-04 14:45:33 +09:00
syuilo
ead5a6a258 APNG support 2019-07-04 14:45:28 +09:00
MeiMei
97002400a8 アバターファイル選択でimage以外は表示しないように (#5098) 2019-07-04 14:31:30 +09:00
syuilo
5e7a4e4752 Fix MIME 2019-07-03 23:43:09 +09:00
syuilo
2c955858a0 Add note 2019-07-03 20:31:52 +09:00
syuilo
a0e56504de Update package.json 2019-07-03 20:31:38 +09:00
Satsuki Yanagi
d46e9f5abe Update ESLint 🚀 (#5097) 2019-07-03 20:20:02 +09:00
Mary
fd94b817ab Implement Webauthn 🎉 (#5088)
* Implement Webauthn 🎉

* Share hexifyAB

* Move hr inside template and add AttestationChallenges janitor daemon

* Apply suggestions from code review

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

* Add newline at the end of file

* Fix stray newline in promise chain

* Ignore var in try{}catch(){} block

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

* Add missing comma

* Add missing semicolon

* Support more attestation formats

* add support for more key types and linter pass

* Refactor

* Refactor

* credentialId --> id

* Fix

* Improve readability

* Add indexes

* fixes for credentialId->id

* Avoid changing store state

* Fix syntax error and code style

* Remove unused import

* Refactor of getkey API

* Create 1561706992953-webauthn.ts

* Update ja-JP.yml

* Add type annotations

* Fix code style

* Specify depedency version

* Fix code style

* Fix janitor daemon and login requesting 2FA regardless of status
2019-07-03 20:18:07 +09:00
syuilo
f17e229c1e Resolve #5072 2019-07-03 03:58:45 +09:00
syuilo
96e23b0e5b MFMで連続したスペースがひとつに纏まるのを修正 2019-07-02 20:52:37 +09:00
syuilo
014b945ea6 Fix test 2019-07-02 20:08:30 +09:00
syuilo
76693138d3 Fix MFM parsing: Ignore parent [] of URL 2019-07-02 20:05:52 +09:00
syuilo
10677b57d4 Update dependencies 🚀 2019-07-02 19:20:34 +09:00
syuilo
5f0ac0f46a Fix #5073 2019-07-02 19:17:14 +09:00
syuilo
7ffe559525 Resolve #5085 2019-07-02 18:32:24 +09:00
Acid Chicken (硫酸鶏)
919e3e2fed Update README.md [AUTOGEN] (#5094) 2019-07-02 15:37:24 +09:00
syuilo
03e999875a リモートファイルの削除が重い問題を修正 2019-07-01 21:12:14 +09:00
syuilo
ed0070c470 Set job concurrency to reduce performance issue 2019-07-01 20:37:26 +09:00
syuilo
d764316708 Simplify log domain 2019-07-01 03:25:31 +09:00
syuilo
06b1203ef9 Create 1561873850023-ChartIndexes.ts 2019-06-30 14:51:57 +09:00
syuilo
b2cf74e878 Create accept-migration.ts 2019-06-30 04:49:30 +09:00
syuilo
21064f7859 Add initial migration 2019-06-29 23:19:21 +09:00
syuilo
bb2d76ffa3 Fix #4926 2019-06-29 23:12:00 +09:00
syuilo
763b70e01b Revert "Update ormconfig.ts"
This reverts commit 5a349eb376.
2019-06-29 15:58:04 +09:00
syuilo
5a349eb376 Update ormconfig.ts 2019-06-29 15:31:54 +09:00
MeiMei
0141affe05 Fix: AP object / actor type (#5086)
* attributedToがArrayの場合などに対応

* attachment以外で来るDocument系のObjectに対応

* Renote, Reply 対応

* 表示をいい感じに

* fix type

* revert as const

* Fix Note / Question type

* attributedToのtypeで複合配列を想定する
2019-06-28 18:54:09 +09:00
syuilo
a8379e3bc9 Use as const
#5089
2019-06-28 16:38:48 +09:00
syuilo
952789cc1e Use as const
#5089
2019-06-27 18:04:09 +09:00
syuilo
0500600cdd Merge branch 'develop' 2019-06-25 01:27:51 +09:00
syuilo
6b897e562a 11.23.1 2019-06-25 01:27:33 +09:00
syuilo
f74bc309b1 Fix bug 2019-06-25 01:24:01 +09:00
syuilo
bc83963ac7 English nyaize 2019-06-24 22:20:13 +09:00
syuilo
94715e6153 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-06-23 16:12:37 +09:00
syuilo
31a5247b9c 🎨 2019-06-23 16:12:11 +09:00
syuilo
ac9f77752d New translations ja-JP.yml (Chinese Simplified) (#5081) 2019-06-23 01:53:21 +09:00
syuilo
73ac2632c2 Merge branch 'develop' 2019-06-23 00:22:33 +09:00
syuilo
20f11a6701 11.23.0 2019-06-23 00:21:58 +09:00
syuilo
9bdc67c1f6 New Crowdin translations (#5065)
* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

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

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

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

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

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Czech)

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

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)
2019-06-23 00:21:04 +09:00
syuilo
bb4ca7b31a Resolve #5010 2019-06-23 00:06:39 +09:00
syuilo
89f16668e6 Fix #4519 2019-06-22 04:17:02 +09:00
syuilo
8409b59dea Improve usability 2019-06-22 04:09:53 +09:00
MeiMei
1707002d43 Block all activities from suspended users (#5076) 2019-06-21 15:42:07 +09:00
MeiMei
16b03fc157 Improve url-preview (#5077)
* url-previewリクエスト時にハッシュは除く

* ハッシュだけ違うプレビューカードは表示しない

*  url-previewをユーザーロケールで出し分けるように

* Fix code style
2019-06-21 15:41:02 +09:00
syuilo
fa0023e541 Fix bug 2019-06-21 15:11:56 +09:00
syuilo
aec5911821 Improve sync 2019-06-21 15:08:17 +09:00
syuilo
26f4c038f3 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-06-21 13:06:55 +09:00
syuilo
6136f6f33a デッキの状態を同期できるように 2019-06-21 13:06:47 +09:00
MeiMei
2b8d0225cc Enable ServiceWorker (#5075) 2019-06-21 11:50:38 +09:00
syuilo
18184441f1 ホームのカスタマイズ情報を複数のデバイス間で同期できるように 2019-06-21 01:50:01 +09:00
syuilo
bd83939993 Provide Redis version 2019-06-20 22:55:57 +09:00
syuilo
2c1932faa7 Add psql version to info page 2019-06-20 22:52:35 +09:00
syuilo
33d79420eb Fix code style 2019-06-19 17:47:24 +09:00
syuilo
80d8af84dd Merge branch 'develop' 2019-06-18 19:16:41 +09:00
syuilo
aac519bf80 11.22.0 2019-06-18 19:15:55 +09:00
syuilo
d64dffbdda Add index 2019-06-18 17:11:28 +09:00
syuilo
4015ccef2f Add chart indices 2019-06-18 17:10:28 +09:00
syuilo
b6f985abaf Update summaly to 2.3.0 2019-06-18 16:58:32 +09:00
syuilo
2dac8d3d1f Update db.vue 2019-06-18 16:53:14 +09:00
syuilo
4f284e1bc0 Resolve #5063 2019-06-18 16:49:58 +09:00
syuilo
b0280355e8 Better request interval 2019-06-18 16:17:20 +09:00
syuilo
048d88b784 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-06-18 15:56:31 +09:00
syuilo
bb52ebdc3e Provide version of postgresql 2019-06-18 15:56:03 +09:00
Satsuki Yanagi
5f2fda85ba Resolve #5069 (#5070) 2019-06-18 15:42:08 +09:00
syuilo
1331f0b953 Use WHATWG API
> New application code should use the WHATWG API.
2019-06-18 15:27:13 +09:00
syuilo
736fdabc1d Fix #2637 2019-06-18 15:19:19 +09:00
syuilo
7096c0ca49 Add note 2019-06-18 14:04:41 +09:00
syuilo
1a984de8e8 Better error handling 2019-06-18 13:58:59 +09:00
syuilo
285d0d13f9 Fix MFM URL parsing 2019-06-17 20:15:19 +09:00
syuilo
63c659bc8f Fix MFM strike parsing 2019-06-16 21:42:57 +09:00
syuilo
af60b45ee7 Fix MFM italic parsing 2019-06-16 21:30:51 +09:00
syuilo
e7effd606d Fix test 2019-06-16 21:30:26 +09:00
syuilo
5042d23bc4 Simplify test 2019-06-16 21:29:31 +09:00
syuilo
b134467bd3 Add some MFM tests 2019-06-16 21:26:43 +09:00
syuilo
5cc1aab530 Merge branch 'develop' 2019-06-16 16:09:04 +09:00
syuilo
49d57ce049 11.21.0 2019-06-16 16:08:36 +09:00
syuilo
f1feceaf1a Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-06-16 16:08:29 +09:00
syuilo
1204e1c5e4 Update dependencies 🚀 2019-06-16 16:07:57 +09:00
syuilo
96cf4c30cf New Crowdin translations (#5053)
* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

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

* New translations ja-JP.yml (Danish)

* New translations ja-JP.yml (Korean)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (French)
2019-06-16 16:06:00 +09:00
MeiMei
a3853611ad Fix: オートコンプリートにアニメーション停止が効かない (#5061) 2019-06-16 16:04:27 +09:00
MeiMei
ef7eaaabfa Support Unicode 12.0 Emoji (#5062) 2019-06-16 14:24:37 +09:00
MeiMei
a4a96710b0 閉鎖しているホストにはAP deliverしないように (#5057)
* 閉鎖しているホストにはAP deliverしないように

* fix case
2019-06-15 17:09:59 +09:00
syuilo
6d08909b2f Refactor 2019-06-15 17:06:03 +09:00
syuilo
2615368b1e Resolve #365 2019-06-15 00:07:41 +09:00
Aya Morisawa
2bd03ca725 Use halfwidth space instead of fullwidth space in code (#5054) 2019-06-14 22:54:19 +09:00
MeiMei
67dda01fcb image以外はproxyしないように (#5051) 2019-06-14 12:14:23 +09:00
syuilo
e9dc54c4d9 サムネイル生成でエラーになってもファイルのアップロードを失敗しないように
#5050
2019-06-13 22:59:15 +09:00
syuilo
fde9fc2891 Make url preview log warn 2019-06-13 22:35:37 +09:00
syuilo
6e59798e82 Merge branch 'develop' 2019-06-13 18:22:49 +09:00
syuilo
5e3cc0a3c6 11.20.4 2019-06-13 18:22:31 +09:00
syuilo
cfb35324d0 Fix bug 2019-06-13 18:15:35 +09:00
syuilo
9bfbc12afa Add indexes 2019-06-13 15:30:51 +09:00
MeiMei
b41cddaf5a Fix: #5035 (#5048) 2019-06-12 13:47:58 +09:00
Satsuki Yanagi
1432a7193d 設定でPostgreSQLのクエリー結果のキャッシュを無効できるように (#5046) 2019-06-11 20:49:08 +09:00
Acid Chicken (硫酸鶏)
20630cb3a0 Update README.md [AUTOGEN] (#5044) 2019-06-11 16:57:52 +09:00
311 changed files with 6320 additions and 2032 deletions

View File

@@ -8,6 +8,9 @@
# Final accessible URL seen by a user. # Final accessible URL seen by a user.
url: https://example.tld/ url: https://example.tld/
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# URL SETTINGS AFTER THAT!
# ┌───────────────────────┐ # ┌───────────────────────┐
#───┘ Port and TLS settings └─────────────────────────────────── #───┘ Port and TLS settings └───────────────────────────────────
@@ -62,6 +65,9 @@ db:
user: example-misskey-user user: example-misskey-user
pass: example-misskey-pass pass: example-misskey-pass
# Whether disable Caching queries
#disableCache: true
# Extra Connection options # Extra Connection options
#extra: #extra:
# ssl: true # ssl: true

View File

@@ -1,23 +1,23 @@
{ {
"parserOptions": { "parserOptions": {
"parser": "typescript-eslint-parser" "parser": "@typescript-eslint/parser"
}, },
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:vue/recommended" "plugin:vue/recommended"
], ],
"rules": { "rules": {
"vue/require-v-for-key": false, "vue/require-v-for-key": 0,
"vue/max-attributes-per-line": false, "vue/max-attributes-per-line": 0,
"vue/html-indent": false, "vue/html-indent": 0,
"vue/html-self-closing": false, "vue/html-self-closing": 0,
"vue/no-unused-vars": false, "vue/no-unused-vars": 0,
"vue/attributes-order": false, "vue/attributes-order": 0,
"vue/require-prop-types": false, "vue/require-prop-types": 0,
"vue/require-default-prop": false, "vue/require-default-prop": 0,
"vue/html-closing-bracket-spacing": false, "vue/html-closing-bracket-spacing": 0,
"vue/singleline-html-element-content-newline": false, "vue/singleline-html-element-content-newline": 0,
"vue/no-v-html": false, "vue/no-v-html": 0,
"no-console": 0, "no-console": 0,
"no-unused-vars": 0, "no-unused-vars": 0,
"no-empty": 0 "no-empty": 0

View File

@@ -1 +1 @@
v12.1.0 v12.6.0

View File

@@ -5,17 +5,122 @@ If you encounter any problems with updating, please try the following:
1. `npm run clean` or `npm run cleanall` 1. `npm run clean` or `npm run cleanall`
2. Retry update (Don't forget `npm i`) 2. Retry update (Don't forget `npm i`)
Migration 11.25.1 (2019/07/09)
------------------------------ --------------------
#### 1 ### 🐛Fixes
``` * ページイベントが正しくストリームに流れてこない問題を修正
npm i -g ts-node * フォントの調整
```
#### 2 11.25.0 (2019/07/08)
``` --------------------
npm run migrate ### ✨Improvements
``` * パスワード無しログイン機能
* MisskeyPagesにイベント送信ボタンを追加
* MisskeyPagesでボタンを目立たせることができるように
* ページをピン留めできるように
* デッキのカラム内でページを見れるように
* 既定のアップロード先フォルダを設定できるように
* ファイルをペーストしてアップロードするときのファイル名をカスタマイズできるように
* 公開以外へのリプライ時元の公開範囲で指定したユーザー情報を引き継ぐように
* デスクトップ版を使うかモバイル版を使うか手動で設定できるように
* フォルダーを削除できないときダイアログボックスで知らせるように
### 🐛Fixes
* postgres redis cache の option が適用されない問題を修正
* 一部MFMテキストが折り返されず突き抜ける問題を修正
11.24.2 (2019/07/05)
--------------------
### 🐛Fixes
* チャートAPIの返り値が文字列になっていることがある問題を修正
* チャートに数字が表示される問題を修正
* ペタバイト単位が表示できない問題を修正
* SingleLineなMFMが折り返されてしまう問題を修正
11.24.1 (2019/07/05)
--------------------
### 🐛Fixes
* WebAuthnでログインできない問題を修正
* 絵文字の変更事項のmetaへの反映が最大時間遅延される問題を修正
* ハッシュタグのトレンドの計算を5分単位で丸めるように
* APNGでもMIME typeはimage/pngにするように
* カスタム絵文字リアクションがたまに文字になってしまう問題を修正
11.24.0 (2019/07/05)
--------------------
### 注意
- このアップデート後に、`node built/tools/accept-migration Init 1000000000000`してください。
- プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### ✨Improvements
* WebAuthnサポート
* APNGサポート
* アバターファイル選択でimage以外は表示しないように
* データベース手動バキューム機能
* メールサーバー設定が正しいか確認できるように
* ピン止めの上限に達したときエラーを表示するように
* AP: attributedTo, to, cc が Array や Object のパターンに対応
* AP: object type が Audio, Document, Image, Page, Video のパターンに対応
* フォロー解除時に確認ダイアログを表示するように
* ユーザー入力ダイアログで、入力時にユーザーの存在を確認するように
### 🐛Fixes
* 自分のインスタンスのルートURIへのリンクが無になる問題を修正
* リモートファイルの削除が重い問題を修正
* 投稿などの連続したスペースがひとつに纏まるのを修正
* MFMのパース修正
* マイグレーション時にエラーが出る問題を修正
11.23.1 (2019/06/25)
--------------------
### 🐛Fixes
* クライアントの設定がリセットされることがある問題を修正
11.23.0 (2019/06/23)
--------------------
### ✨Improvements
* ホーム/デッキのカスタマイズ情報を複数のデバイスで同期できるように
* ホーム/デッキのカスタマイズ情報の複数プリセット切り替え
* サーバー情報にRedisのバージョンを追加
* ServiceWorker有効化
* MisskeyPagesでリストの要素数を取得する関数を追加
* URLプレビューでハッシュだけ違うプレビューカードは表示しないように
* URLプレビューをユーザーロケールで出し分けるように
* リモートの凍結されたアカウントからのアクティビティはすべて無視するように
### 🐛Fixes
* フォロー解除してもフォローボタンがフォロー中のままになる問題を修正
11.22.0 (2019/06/18)
--------------------
### ✨Improvements
* 管理画面でデータベースの各テーブルのレコード数やサイズを確認できるように
* サーバー情報にPostgreSQLのバージョンを追加
### 🐛Fixes
* リモートファイルのダウンロードに失敗することがある問題を修正
* アンケートの期間を日時指定で選択すると日時がUTCになってしまう問題を修正
* MFMのパースを修正
11.21.0 (2019/06/16)
--------------------
### ✨Improvements
* Unicode 12.0 の絵文字に対応
* 閉鎖しているホストにはAP deliverしないように
* image以外はproxyしないように
### 🐛Fixes
* サムネイル生成でエラーになるとファイルのアップロードに失敗する問題を修正
* オートコンプリートにアニメーション停止が効かない問題を修正
11.20.4 (2019/06/13)
--------------------
### 🐛Fixes
* 検索結果がループする問題を修正
* 設定でPostgreSQLのクエリー結果のキャッシュを無効できるように
* 「投稿内の動きのあるテキストを無効にする」だけ反応しない問題を修正
* 特定の操作のデータベースのパフォーマンス調整
11.20.3 (2019/06/10) 11.20.3 (2019/06/10)
-------------------- --------------------
@@ -538,10 +643,9 @@ mongodb:
3. migration ブランチに切り替え 3. migration ブランチに切り替え
4. `npm i` 4. `npm i`
5. `npm run build` 5. `npm run build`
6. `npm run init` 6. `npm run migrate`
7. `npm run migrate` 7. master ブランチに戻す
8. master ブランチに戻す 8. enjoy
9. enjoy
10.100.0 10.100.0
---------- ----------

View File

@@ -219,11 +219,8 @@ const user = await Users.findOne(userId).then(ensure);
``` ```
### Migration作成方法 ### Migration作成方法
コードの変更をした後、`ormconfig.json``npm run ormconfig`で生成)を用意し、
``` ```
npm i -g ts-node npx ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前
ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前
``` ```
作成されたスクリプトは不必要な変更を含むため除去してください。 作成されたスクリプトは不必要な変更を含むため除去してください。

View File

@@ -1,4 +1,4 @@
FROM node:12.1-alpine AS base FROM node:12.6-alpine AS base
ENV NODE_ENV=production ENV NODE_ENV=production

View File

@@ -124,7 +124,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<table><tr> <table><tr>
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" 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/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/12021162/963128bb8d14476dbd8407943db8f31a/1.png?token-time=2145916800&token-hash=FMV7cPKBD1TU2WTbl1jg6AcdKSvTb2BSFcDhgc-EO8w%3D" alt="gutfuckllc" 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://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/12718187" alt="Peter G." width="100"></td> <td><img src="https://c8.patreon.com/2/200/12718187" alt="Peter G." width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1.jpe?token-time=2145916800&token-hash=UQRWf01TwHDV4Cls1K0YAOAjM29ssif7hLVq0ESQ0hs%3D" alt="nemu" width="100"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1.jpe?token-time=2145916800&token-hash=UQRWf01TwHDV4Cls1K0YAOAjM29ssif7hLVq0ESQ0hs%3D" alt="nemu" width="100"></td>
@@ -135,7 +134,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
</tr><tr> </tr><tr>
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</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/Yuzulia">YuzuRyo61</a></td>
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td> <td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td> <td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td> <td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
@@ -147,7 +145,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<table><tr> <table><tr>
<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/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/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/17195955/be45e5e14c3e48b2bee0456c84e19df4/4.jpe?token-time=2145916800&token-hash=UslrPVM-8TXOe8AapuNiaFYjcIJgPNcU-fKpGbfGJNI%3D" alt="Damillora" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%3D" alt="Atsuko Tominaga" width="100"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%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/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/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1.jpe?token-time=2145916800&token-hash=EWxXhVbZYH7KB4IDT3joc8TbIg8zPO40x1r5IDn3R7c%3D" alt="Hiratake" width="100"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1.jpe?token-time=2145916800&token-hash=EWxXhVbZYH7KB4IDT3joc8TbIg8zPO40x1r5IDn3R7c%3D" alt="Hiratake" width="100"></td>
@@ -158,7 +155,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
</tr><tr> </tr><tr>
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</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/takimura">takimura</a></td>
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td> <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/user?u=4389829">natalie</a></td>
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td> <td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
@@ -179,7 +175,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td> <td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table> </tr></table>
**Last updated:** Tue, 04 Jun 2019 04:21:06 UTC **Last updated:** Mon, 01 Jul 2019 21:44:06 UTC
<!-- PATREON_END --> <!-- PATREON_END -->
:four_leaf_clover: Copyright :four_leaf_clover: Copyright

View File

@@ -132,7 +132,7 @@ You can check if the service is running with `systemctl status misskey`.
2. `git pull` 2. `git pull`
3. `npm install` 3. `npm install`
4. `NODE_ENV=production npm run build` 4. `NODE_ENV=production npm run build`
5. Check [ChangeLog](../CHANGELOG.md) for migration information 5. `npm run migrate`
6. Restart your Misskey process to apply changes 6. Restart your Misskey process to apply changes
7. Enjoy 7. Enjoy

View File

@@ -126,7 +126,7 @@ Vous pouvez vérifier si le service a démarré en utilisant la commande `system
2. `git pull` 2. `git pull`
3. `npm install` 3. `npm install`
4. `NODE_ENV=production npm run build` 4. `NODE_ENV=production npm run build`
5. Consultez [ChangeLog](../CHANGELOG.md) pour les information de migration. 5. `npm run migrate`
---------------------------------------------------------------- ----------------------------------------------------------------

View File

@@ -133,7 +133,7 @@ npm run init
2. `git pull` 2. `git pull`
3. `npm install` 3. `npm install`
4. `NODE_ENV=production npm run build` 4. `NODE_ENV=production npm run build`
5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する 5. `npm run migrate`
なにか問題が発生した場合は、`npm run clean`または`npm run cleanall`すると直る場合があります。 なにか問題が発生した場合は、`npm run clean`または`npm run cleanall`すると直る場合があります。

View File

@@ -94,9 +94,21 @@ common:
follow-users-to-make-your-timeline: "Poznámky sledujících se zobrazí ve vaší časové ose" follow-users-to-make-your-timeline: "Poznámky sledujících se zobrazí ve vaší časové ose"
explore: "Najít uživatele" explore: "Najít uživatele"
post-form: post-form:
attach-location-information: "Přidat informace o lokaci"
hide-contents: "Schovat obsah"
reply-placeholder: "Odpovědět na tento příspěvek"
quote-placeholder: "Citovat tento příspěvek"
submit: "Odeslat" submit: "Odeslat"
reply: "Odpovědět" reply: "Odpovědět"
renote: "Renotovat" renote: "Renotovat"
posting: "Posílání"
attach-media-from-local: "Nahrát soubor z vašeho zařízení"
insert-a-kao: "v('ω')v"
create-poll: "Vytvořit anketu"
text-remain: "zbývá ještě {} znaků"
recent-tags: "Nejnovější"
visibility: "Viditelnost"
geolocation-alert: "Vaše zařízení nedalo k dispozici lokaci"
error: "Chyba" error: "Chyba"
enter-username: "Zadejte své uživatelské jméno" enter-username: "Zadejte své uživatelské jméno"
add-visible-user: "Přidat uživatele" add-visible-user: "Přidat uživatele"
@@ -249,6 +261,7 @@ common:
disable-via-mobile: "Neoznačovat příspěvky jako „z mobilu“" disable-via-mobile: "Neoznačovat příspěvky jako „z mobilu“"
load-raw-images: "Zobrazovat obrázky v původní kvalitě" load-raw-images: "Zobrazovat obrázky v původní kvalitě"
load-remote-media: "Zobrazovat média ze vzdáleného serveru" load-remote-media: "Zobrazovat média ze vzdáleného serveru"
sync: "Synchronizace"
search: "Hledání" search: "Hledání"
delete: "Odstranit" delete: "Odstranit"
loading: "Načítám..." loading: "Načítám..."
@@ -316,7 +329,10 @@ auth/views/form.vue:
accept: "Povolit přístup" accept: "Povolit přístup"
auth/views/index.vue: auth/views/index.vue:
loading: "Načítám..." loading: "Načítám..."
denied-paragraph: "Tato aplikace nebude mít přístup k Vašemu účtu."
already-authorized: "Tato aplikace byla již autorizována." already-authorized: "Tato aplikace byla již autorizována."
callback-url: "Zpátky do aplikace."
please-go-back: "Prosím vraťte se zpátky do aplikace."
error: "Taková relace neexistuje." error: "Taková relace neexistuje."
sign-in: "Prosím přihlaste se." sign-in: "Prosím přihlaste se."
common/views/pages/explore.vue: common/views/pages/explore.vue:
@@ -366,20 +382,25 @@ common/views/components/games/reversi/reversi.room.vue:
waiting-for-both: "Připravuji" waiting-for-both: "Připravuji"
cancel: "Zrušit" cancel: "Zrušit"
ready: "Připraveno" ready: "Připraveno"
cancel-ready: "Pokračovat v přípravě"
common/views/components/connect-failed.vue: common/views/components/connect-failed.vue:
title: "Nelze se připojit k serveru" title: "Nelze se připojit k serveru"
description: "Nastal problém s Vaším připojením k internetu, nebo server není dostupný nebo zrovna probíhá údržba. Prosím {zkuste to znova} za pár minut." description: "Nastal problém s Vaším připojením k internetu, nebo server není dostupný nebo zrovna probíhá údržba. Prosím {zkuste to znova} za pár minut."
thanks: "Děkujeme že jste použili Misskey." thanks: "Děkujeme že jste použili Misskey."
common/views/components/connect-failed.troubleshooter.vue: common/views/components/connect-failed.troubleshooter.vue:
title: "Poradce při potížích"
network: "Síťové připojení" network: "Síťové připojení"
checking-network: "Prověřit síťové připojení" checking-network: "Prověřit síťové připojení"
internet: "Připojení k internetu" internet: "Připojení k internetu"
checking-internet: "Ověřuji připojení k internetu." checking-internet: "Ověřuji připojení k internetu."
server: "Připojení k serveru" server: "Připojení k serveru"
checking-server: "Spojuji se se serverem"
no-network-desc: "Ujistěte se že jste připojeni k Internetu." no-network-desc: "Ujistěte se že jste připojeni k Internetu."
no-internet: "Nejste připojeni k internetu" no-internet: "Nejste připojeni k internetu"
no-internet-desc: "Jste připojen k síti, ale zdá se že stále chybí připojení k Internetu. Prosím zkontrolujte Vaše připojení k Internetu." no-internet-desc: "Jste připojen k síti, ale zdá se že stále chybí připojení k Internetu. Prosím zkontrolujte Vaše připojení k Internetu."
no-server: "Nelze se připojit k serveru Misskey" no-server: "Nelze se připojit k serveru Misskey"
success: "Úspěšně se podařilo spojit s Misskey serverem"
flush: "Vyčistit mezipaměť"
common/views/components/media-banner.vue: common/views/components/media-banner.vue:
sensitive: "Choulostivý obsah" sensitive: "Choulostivý obsah"
click-to-show: "Klikněte pro zobrazení" click-to-show: "Klikněte pro zobrazení"
@@ -403,8 +424,10 @@ common/views/components/theme.vue:
find-more-theme: "Najít další vzhledy" find-more-theme: "Najít další vzhledy"
theme-name: "Jméno vzhledu" theme-name: "Jméno vzhledu"
preview-created-theme: "Náhled" preview-created-theme: "Náhled"
invalid-theme: "Vzhled není validní"
already-installed: "Tento vzhled je již nainstalován." already-installed: "Tento vzhled je již nainstalován."
saved: "Uloženo" saved: "Uloženo"
manage-themes: "Správa vzhledů"
builtin-themes: "Standardní vzhledy" builtin-themes: "Standardní vzhledy"
my-themes: "Moje vzhledy" my-themes: "Moje vzhledy"
installed-themes: "Nainstalované vzhledy" installed-themes: "Nainstalované vzhledy"
@@ -415,6 +438,7 @@ common/views/components/theme.vue:
desc: "Popis" desc: "Popis"
export: "Exportovat" export: "Exportovat"
import: "Importovat" import: "Importovat"
import-by-code: "nebo zkopírujte kód"
theme-name-required: "Jméno vzhledu je povinné" theme-name-required: "Jméno vzhledu je povinné"
common/views/components/cw-button.vue: common/views/components/cw-button.vue:
hide: "Skrýt" hide: "Skrýt"
@@ -427,6 +451,7 @@ common/views/components/messaging.vue:
you: "Vy" you: "Vy"
no-history: "Žádná historie" no-history: "Žádná historie"
user: "Uživatel" user: "Uživatel"
group: "Skupina"
common/views/components/messaging-room.vue: common/views/components/messaging-room.vue:
new-message: "Máte novou zprávu" new-message: "Máte novou zprávu"
common/views/components/messaging-room.form.vue: common/views/components/messaging-room.form.vue:
@@ -444,6 +469,7 @@ common/views/components/nav.vue:
repository: "Úložiště" repository: "Úložiště"
develop: "Vývojáři" develop: "Vývojáři"
feedback: "Zpětná vazba" feedback: "Zpětná vazba"
tos: "Podmínky užívání"
common/views/components/note-menu.vue: common/views/components/note-menu.vue:
mention: "Zmínění" mention: "Zmínění"
detail: "Více" detail: "Více"
@@ -487,10 +513,13 @@ common/views/components/poll-editor.vue:
remove: "Odstranit tuto možnost" remove: "Odstranit tuto možnost"
add: "+ Přidat možnost" add: "+ Přidat možnost"
destroy: "Zahodit dotazník" destroy: "Zahodit dotazník"
multiple: "Více odpovědí je povoleno"
expiration: "Termín" expiration: "Termín"
infinite: "Nekonečne" infinite: "Nekonečne"
at: "Výběr data a času" at: "Výběr data a času"
no-more: "Více už přidat nemůžete"
deadline-date: "Termín ukončení" deadline-date: "Termín ukončení"
deadline-time: "Doba trvání"
interval: "Trvání" interval: "Trvání"
second: "Sekunda" second: "Sekunda"
minute: "Minuta" minute: "Minuta"
@@ -498,6 +527,7 @@ common/views/components/poll-editor.vue:
day: "Ne" day: "Ne"
common/views/components/reaction-picker.vue: common/views/components/reaction-picker.vue:
choose-reaction: "Vyberte svoji reakci" choose-reaction: "Vyberte svoji reakci"
input-reaction-placeholder: "nebo vložte Emoji"
common/views/components/emoji-picker.vue: common/views/components/emoji-picker.vue:
custom-emoji: "Emoji" custom-emoji: "Emoji"
people: "Lidé" people: "Lidé"
@@ -508,9 +538,12 @@ common/views/components/emoji-picker.vue:
objects: "Objekty" objects: "Objekty"
symbols: "Symboly" symbols: "Symboly"
flags: "Vlajky" flags: "Vlajky"
common/views/components/settings/app-type.vue:
info: "Pro aktivování změn musíte znovu načíst stránky."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "Přezdívka" username: "Přezdívka"
password: "Heslo" password: "Heslo"
token: "Token"
signing-in: "Přihlašování..." signing-in: "Přihlašování..."
or: "Nebo" or: "Nebo"
signin-with-twitter: "Přihlásit se pomocí účtu Twitter" signin-with-twitter: "Přihlásit se pomocí účtu Twitter"
@@ -538,6 +571,7 @@ common/views/components/signup.vue:
password-matched: "OK" password-matched: "OK"
password-not-matched: "Neshodují se" password-not-matched: "Neshodují se"
recaptcha: "Potvrzení" recaptcha: "Potvrzení"
tos: "Podmínky užívání"
create: "Vytvořit účet" create: "Vytvořit účet"
some-error: "Pokus o vytvoření účtu selhal. Prosím zkuste to znovu." some-error: "Pokus o vytvoření účtu selhal. Prosím zkuste to znovu."
common/views/components/special-message.vue: common/views/components/special-message.vue:
@@ -576,6 +610,7 @@ common/views/components/visibility-chooser.vue:
home: "Domů" home: "Domů"
specified-desc: "Poslat pouze zmíněným uživatelům" specified-desc: "Poslat pouze zmíněným uživatelům"
local-public: "Veřejná (pouze místní)" local-public: "Veřejná (pouze místní)"
local-public-desc: "Nepublikovat na vzdálených serverech"
local-home: "Domovská (pouze místní)" local-home: "Domovská (pouze místní)"
local-followers: "Pro sledující (pouze místní)" local-followers: "Pro sledující (pouze místní)"
common/views/components/trends.vue: common/views/components/trends.vue:
@@ -585,6 +620,8 @@ common/views/components/language-settings.vue:
title: "Zobrazit jazyky" title: "Zobrazit jazyky"
pick-language: "Zvolte jazyk" pick-language: "Zvolte jazyk"
recommended: "Doporučené" recommended: "Doporučené"
auto: "Automaticky"
specify-language: "Vyberte jazyk"
info: "Pro aktivování změn musíte znovu načíst stránky." info: "Pro aktivování změn musíte znovu načíst stránky."
common/views/components/profile-editor.vue: common/views/components/profile-editor.vue:
title: "Profil" title: "Profil"
@@ -611,6 +648,7 @@ common/views/components/profile-editor.vue:
email-not-verified: "Váš email není potvrzen. Prosím zkontrolujte si svou schránku." email-not-verified: "Váš email není potvrzen. Prosím zkontrolujte si svou schránku."
export: "Exportovat" export: "Exportovat"
import: "Importovat" import: "Importovat"
export-and-import: "Import / Export"
export-targets: export-targets:
following-list: "Seznam sledujících" following-list: "Seznam sledujících"
mute-list: "Seznam ztlumených uživatelů" mute-list: "Seznam ztlumených uživatelů"
@@ -630,19 +668,31 @@ common/views/components/user-list-editor.vue:
add-user: "Přidat uživatele" add-user: "Přidat uživatele"
common/views/components/user-group-editor.vue: common/views/components/user-group-editor.vue:
users: "Členové" users: "Členové"
rename: "Přejmenovat skupinu"
delete: "Odstranit skupinu"
transfer: "Přesunout skupinu" transfer: "Přesunout skupinu"
transfer-are-you-sure: "Jste si jistí že chcete přidat @$2 do skupiny: $1?"
transferred: "Skupina přesunuta" transferred: "Skupina přesunuta"
remove-user: "Odebrat uživatele z této skupiny"
delete-are-you-sure: "Jste si jistí že chcete smazat skupinu \"$1\"?"
deleted: "Smazáno" deleted: "Smazáno"
invite: "Pozvat" invite: "Pozvat"
invited: "Pozvánka byla úspěšně odeslána"
common/views/components/user-lists.vue: common/views/components/user-lists.vue:
user-lists: "Seznamy" user-lists: "Seznamy"
create-list: "Vytvořit seznam"
list-name: "Název seznamu" list-name: "Název seznamu"
common/views/components/user-groups.vue: common/views/components/user-groups.vue:
user-groups: "Skupiny" user-groups: "Skupiny"
create-group: "Vytvořit skupinu"
group-name: "Název skupiny"
owned-groups: "Moje skupiny"
invites: "Pozvat" invites: "Pozvat"
reject-invite: "Odmítnout" reject-invite: "Odmítnout"
common/views/widgets/broadcast.vue: common/views/widgets/broadcast.vue:
fetching: "Načítám" fetching: "Načítám"
no-broadcasts: "Žádná nová oznámení"
have-a-nice-day: "Přejeme Vám příjemný den!"
next: "Další" next: "Další"
common/views/widgets/calendar.vue: common/views/widgets/calendar.vue:
year: "Rok {}" year: "Rok {}"
@@ -717,7 +767,7 @@ desktop/views/components/drive.file.vue:
rename: "Přejmenovat" rename: "Přejmenovat"
copy-url: "Kopírovat URL" copy-url: "Kopírovat URL"
download: "Stáhnout" download: "Stáhnout"
else-files: "Více..." else-files: "Ostatní"
set-as-avatar: "Nastavit jako avatar" set-as-avatar: "Nastavit jako avatar"
set-as-banner: "Nastavit jako baner" set-as-banner: "Nastavit jako baner"
open-in-app: "Otevřít v aplikaci" open-in-app: "Otevřít v aplikaci"
@@ -735,6 +785,7 @@ desktop/views/components/drive.folder.vue:
rename: "Přejmenovat" rename: "Přejmenovat"
rename-folder: "Přejmenovat složku" rename-folder: "Přejmenovat složku"
input-new-folder-name: "Zadejte nové jméno" input-new-folder-name: "Zadejte nové jméno"
else-folders: "Ostatní"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
empty-drive-description: "Klikněte pravým tlačítkem myši pro otevření menu, nebo sem přetáhněte soubor pro nahrání." empty-drive-description: "Klikněte pravým tlačítkem myši pro otevření menu, nebo sem přetáhněte soubor pro nahrání."
empty-folder: "Tato složka je prázdná" empty-folder: "Tato složka je prázdná"
@@ -800,6 +851,7 @@ desktop/views/components/renote-form-window.vue:
desktop/views/components/settings.2fa.vue: desktop/views/components/settings.2fa.vue:
detail: "Více…" detail: "Více…"
url: "https://www.google.cz/landing/2step/" url: "https://www.google.cz/landing/2step/"
token: "Token"
common/views/components/media-image.vue: common/views/components/media-image.vue:
click-to-show: "Klikněte pro zobrazení" click-to-show: "Klikněte pro zobrazení"
common/views/components/api-settings.vue: common/views/components/api-settings.vue:
@@ -939,6 +991,7 @@ admin/views/instance.vue:
smtp-auth: "Provést SMTP autentikaci" smtp-auth: "Provést SMTP autentikaci"
smtp-user: "SMTP uživatel" smtp-user: "SMTP uživatel"
smtp-pass: "SMTP heslo" smtp-pass: "SMTP heslo"
test-email: "Test"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "Povolit ServiceWorker" enable-serviceworker: "Povolit ServiceWorker"
vapid-publickey: "VAPID veřejný klíč" vapid-publickey: "VAPID veřejný klíč"
@@ -1216,6 +1269,8 @@ deck/deck.user-column.vue:
dev/views/new-app.vue: dev/views/new-app.vue:
app-name-desc: "Jméno vaší aplikace" app-name-desc: "Jméno vaší aplikace"
pages: pages:
pin-this-page: "Připnout"
unpin-this-page: "Odepnout"
like: "Lajk" like: "Lajk"
title: "Titulek" title: "Titulek"
blocks: blocks:
@@ -1253,5 +1308,7 @@ pages:
arg2: "Seznamy" arg2: "Seznamy"
_pick: _pick:
arg1: "Seznamy" arg1: "Seznamy"
_listLen:
arg1: "Seznamy"
types: types:
array: "Seznamy" array: "Seznamy"

View File

@@ -568,6 +568,8 @@ common/views/components/emoji-picker.vue:
objects: "Objekt" objects: "Objekt"
symbols: "Symboler" symbols: "Symboler"
flags: "Flag" flags: "Flag"
common/views/components/settings/app-type.vue:
info: "Du er nødt til at genindlæse siden, før ændringerne slår igennem."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "Brugernavn" username: "Brugernavn"
password: "Adgangskode" password: "Adgangskode"
@@ -847,7 +849,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "Fjern markering som 'følsom'" unmark-as-sensitive: "Fjern markering som 'følsom'"
copy-url: "Kopier webadresse" copy-url: "Kopier webadresse"
download: "Download" download: "Download"
else-files: "Andre" else-files: "Avanceret"
set-as-avatar: "Vælg som avatar" set-as-avatar: "Vælg som avatar"
set-as-banner: "Vælg som banner" set-as-banner: "Vælg som banner"
open-in-app: "Åbn i app" open-in-app: "Åbn i app"
@@ -866,6 +868,7 @@ desktop/views/components/drive.folder.vue:
rename: "Omdøb" rename: "Omdøb"
rename-folder: "Omdøb mappe" rename-folder: "Omdøb mappe"
input-new-folder-name: "Angiv nyt navn" input-new-folder-name: "Angiv nyt navn"
else-folders: "Avanceret"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "Søg" search: "Søg"
empty-draghover: "Smid det her! Fordi du ved, at jeg er meget sød, ikke?" empty-draghover: "Smid det her! Fordi du ved, at jeg er meget sød, ikke?"
@@ -995,6 +998,7 @@ common/views/components/drive-settings.vue:
max: "Kapacitet" max: "Kapacitet"
in-use: "I brug" in-use: "I brug"
stats: "Statistik" stats: "Statistik"
default-upload-folder-name: "Mappe(r)"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "Annuller / Bloker" mute-and-block: "Annuller / Bloker"
mute: "Annuller" mute: "Annuller"
@@ -1195,6 +1199,7 @@ admin/views/instance.vue:
smtp-auth: "Udfør autentifikation af SMTP" smtp-auth: "Udfør autentifikation af SMTP"
smtp-user: "SMTP bruger" smtp-user: "SMTP bruger"
smtp-pass: "SMTP adgangskode" smtp-pass: "SMTP adgangskode"
test-email: "Test"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "Aktiver ServiceWorker" enable-serviceworker: "Aktiver ServiceWorker"
serviceworker-info: "Skal være aktiveret for at give push notifikationer." serviceworker-info: "Skal være aktiveret for at give push notifikationer."
@@ -1663,6 +1668,8 @@ dev/views/new-app.vue:
app-name: "Navn på app" app-name: "Navn på app"
app-name-placeholder: "F.eks. Misskey for iOS" app-name-placeholder: "F.eks. Misskey for iOS"
pages: pages:
pin-this-page: "Tilknyt til din profil"
unpin-this-page: "Fjern tilknytning til din profil"
like: "Synes om" like: "Synes om"
title: "Titel" title: "Titel"
blocks: blocks:
@@ -1761,8 +1768,7 @@ pages:
_divide: _divide:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
remind: "÷ Tomo" _mod:
_remind:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
eq: "A og B er ens" eq: "A og B er ens"
@@ -1845,6 +1851,8 @@ pages:
_pick: _pick:
arg1: "Lister" arg1: "Lister"
arg2: "Position" arg2: "Position"
_listLen:
arg1: "Lister"
number: "Tal" number: "Tal"
stringToNumber: "Tekst til tal" stringToNumber: "Tekst til tal"
_stringToNumber: _stringToNumber:

View File

@@ -632,7 +632,6 @@ desktop/views/components/drive.file.vue:
rename: "Umbenennen" rename: "Umbenennen"
copy-url: "URL kopieren" copy-url: "URL kopieren"
download: "Download" download: "Download"
else-files: "Anderes…"
set-as-avatar: "Als Avatar festlegen" set-as-avatar: "Als Avatar festlegen"
set-as-banner: "Setze als Banner" set-as-banner: "Setze als Banner"
open-in-app: "In der App öffnen" open-in-app: "In der App öffnen"
@@ -775,6 +774,7 @@ admin/views/instance.vue:
invite: "Einladen" invite: "Einladen"
save: "Speichern" save: "Speichern"
saved: "Gespeichert" saved: "Gespeichert"
test-email: "Test"
admin/views/charts.vue: admin/views/charts.vue:
drive: "Drive" drive: "Drive"
admin/views/drive.vue: admin/views/drive.vue:
@@ -910,6 +910,8 @@ dev/views/new-app.vue:
authority-desc: "Nur die hier eingetragenen Berechtigungen, werden per API zur Verfügung stehen." 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." authority-warning: "Dies kann auch nach dem erstellen der Anwendung geändert werden, allerdings werden dann alle bisher generierten Token ungültig."
pages: pages:
pin-this-page: "An die Profilseite pinnen"
unpin-this-page: "Lösen"
like: "Gefällt mir" like: "Gefällt mir"
blocks: blocks:
post: "\"Neuer Beitrag\"-Formular" post: "\"Neuer Beitrag\"-Formular"
@@ -929,5 +931,7 @@ pages:
arg2: "Listen" arg2: "Listen"
_pick: _pick:
arg1: "Listen" arg1: "Listen"
_listLen:
arg1: "Listen"
types: types:
array: "Listen" array: "Listen"

View File

@@ -35,6 +35,7 @@ common:
signout: "Logout" signout: "Logout"
reload-to-apply-the-setting: "You'll need to reload the page to reflect this setting. Do you want to reload it now?" reload-to-apply-the-setting: "You'll need to reload the page to reflect this setting. Do you want to reload it now?"
fetching-as-ap-object: "Inquiring to union" fetching-as-ap-object: "Inquiring to union"
unfollow-confirm: "Do you want to unfollow {name}?"
got-it: "Got it!" got-it: "Got it!"
customization-tips: customization-tips:
title: "Customization tips" title: "Customization tips"
@@ -122,6 +123,7 @@ common:
add-visible-user: "Add a user" add-visible-user: "Add a user"
cw-placeholder: "Comments for the post (optional)" cw-placeholder: "Comments for the post (optional)"
username-prompt: "Please enter username" username-prompt: "Please enter username"
enter-file-name: "Edit file name"
weekday-short: weekday-short:
sunday: "S" sunday: "S"
monday: "M" monday: "M"
@@ -188,6 +190,11 @@ common:
remember-note-visibility: "Remember post visibility" remember-note-visibility: "Remember post visibility"
web-search-engine: "Web search engine" web-search-engine: "Web search engine"
web-search-engine-desc: "Example: https://www.google.com/?#q={{query}}" web-search-engine-desc: "Example: https://www.google.com/?#q={{query}}"
paste: "Paste"
pasted-file-name: "Template for pasted file name"
pasted-file-name-desc: "Example: \"yyyy-MM-dd HH-mm-ss [{{number}}]\" → \"2018-03-20 21-30-24 1\""
paste-dialog: "Edit the pasted file name"
paste-dialog-desc: "Display a dialog to edit the file name when you paste a file."
keep-cw: "Preserve content warning" keep-cw: "Preserve content warning"
keep-cw-desc: "When replying to a post, the same content warning is set by default to the reply, as has been set by the original post." keep-cw-desc: "When replying to a post, the same content warning is set by default to the reply, as has been set by the original post."
i-like-sushi: "I prefer sushi rather than pudding" i-like-sushi: "I prefer sushi rather than pudding"
@@ -270,6 +277,9 @@ common:
disable-via-mobile: "Don't mark the post as 'from mobile'" disable-via-mobile: "Don't mark the post as 'from mobile'"
load-raw-images: "Show attached images in original quality" load-raw-images: "Show attached images in original quality"
load-remote-media: "Show media from a remote server" load-remote-media: "Show media from a remote server"
sync: "Sync"
home-profile: "Home profile"
deck-profile: "Deck profile"
search: "Search" search: "Search"
delete: "Delete" delete: "Delete"
loading: "Loading" loading: "Loading"
@@ -520,6 +530,7 @@ common/views/components/note-menu.vue:
delete: "Delete" delete: "Delete"
delete-confirm: "Are you sure you want to delete this post?" delete-confirm: "Are you sure you want to delete this post?"
remote: "Show original note" remote: "Show original note"
pin-limit-exceeded: "You can't pin any more posts."
common/views/components/user-menu.vue: common/views/components/user-menu.vue:
mention: "Mention" mention: "Mention"
mute: "Mute" mute: "Mute"
@@ -588,6 +599,14 @@ common/views/components/emoji-picker.vue:
objects: "Objects" objects: "Objects"
symbols: "Symbols" symbols: "Symbols"
flags: "Flags" flags: "Flags"
common/views/components/settings/app-type.vue:
title: "Mode"
intro: "You can specify whether you want to use the desktop, or the mobile layout."
choices:
auto: "Choose layout automatically"
desktop: "Always use the desktop layout"
mobile: "Always use the mobile layout"
info: "You need to reload the page for the changes to take effect."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "Username" username: "Username"
password: "Password" password: "Password"
@@ -598,6 +617,8 @@ common/views/components/signin.vue:
signin-with-github: "Sign in with GitHub" signin-with-github: "Sign in with GitHub"
signin-with-discord: "Sign in with Discord" signin-with-discord: "Sign in with Discord"
login-failed: "Logging in has failed. Make sure you have entered the correct username and password." login-failed: "Logging in has failed. Make sure you have entered the correct username and password."
tap-key: "Click on the Security Key to log in"
enter-2fa-code: "Enter your verification code"
common/views/components/signup.vue: common/views/components/signup.vue:
invitation-code: "Invitation code" invitation-code: "Invitation code"
invitation-info: "If you do not have an invitation code, please contact an <a href=\"{}\">administrator</a>." invitation-info: "If you do not have an invitation code, please contact an <a href=\"{}\">administrator</a>."
@@ -870,7 +891,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "Unmark as 'sensitive'" unmark-as-sensitive: "Unmark as 'sensitive'"
copy-url: "Copy URL" copy-url: "Copy URL"
download: "Download" download: "Download"
else-files: "Others" else-files: "Other"
set-as-avatar: "Set as an avatar" set-as-avatar: "Set as an avatar"
set-as-banner: "Set as a banner" set-as-banner: "Set as a banner"
open-in-app: "Open in app" open-in-app: "Open in app"
@@ -880,15 +901,20 @@ desktop/views/components/drive.file.vue:
copied: "Copied" copied: "Copied"
copied-url-to-clipboard: "URL has been copied to clipboard" copied-url-to-clipboard: "URL has been copied to clipboard"
desktop/views/components/drive.folder.vue: desktop/views/components/drive.folder.vue:
upload-folder: "Default Upload location"
unable-to-process: "The operation could not be completed." unable-to-process: "The operation could not be completed."
circular-reference-detected: "The destination folder is a subfolder of the folder you wish to move." circular-reference-detected: "The destination folder is a subfolder of the folder you wish to move."
unhandled-error: "Unknown error" unhandled-error: "Unknown error"
unable-to-delete: "Unable to delete"
has-child-files-or-folders: "Since this folder is not empty, it can not be deleted."
contextmenu: contextmenu:
move-to-this-folder: "Move to this folder" move-to-this-folder: "Move to this folder"
show-in-new-window: "Open in new window" show-in-new-window: "Open in new window"
rename: "Rename" rename: "Rename"
rename-folder: "Rename folder" rename-folder: "Rename folder"
input-new-folder-name: "Enter new name" input-new-folder-name: "Enter new name"
else-folders: "Other"
set-as-upload-folder: "Set as default upload folder"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "Search" search: "Search"
empty-draghover: "Drop it here! Yep, cuz you know I'm cute, right?" empty-draghover: "Drop it here! Yep, cuz you know I'm cute, right?"
@@ -994,6 +1020,16 @@ desktop/views/components/settings.2fa.vue:
success: "Settings saved!" success: "Settings saved!"
failed: "Failed to setup. Please ensure that the token is correct." failed: "Failed to setup. Please ensure that the token is correct."
info: "From the next time you sign in to Misskey, the token displayed on your device will be necessary too, as well as the password." info: "From the next time you sign in to Misskey, the token displayed on your device will be necessary too, as well as the password."
totp-header: "Authenticator App"
security-key-header: "Security Key"
security-key: "For additional security, you can log in to your account using a hardware Security Key that supports FIDO2. When you then sign in, you'll need the registered Security Key, or an authenticator app with you."
last-used: "Last used:"
activate-key: "Click to activate the Security Key"
security-key-name: "Name the Key"
register-security-key: "Complete Key registration"
something-went-wrong: "Wow! There was a problem registering the Key:"
key-unregistered: "The Key has been deleted"
use-password-less-login: "Use Password-less login"
common/views/components/media-image.vue: common/views/components/media-image.vue:
sensitive: "NSFW" sensitive: "NSFW"
click-to-show: "Click to show" click-to-show: "Click to show"
@@ -1018,6 +1054,9 @@ common/views/components/drive-settings.vue:
max: "Max" max: "Max"
in-use: "In use" in-use: "In use"
stats: "Statistics" stats: "Statistics"
default-upload-folder: "Default upload folder location"
default-upload-folder-name: "Folder(s)"
change-default-upload-folder: "Change folder"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "Mute / Block" mute-and-block: "Mute / Block"
mute: "Mute" mute: "Mute"
@@ -1103,7 +1142,13 @@ admin/views/index.vue:
abuse: "Abuse" abuse: "Abuse"
queue: "Job Queue" queue: "Job Queue"
logs: "Logs" logs: "Logs"
db: "Database"
back-to-misskey: "Back to Misskey" back-to-misskey: "Back to Misskey"
admin/views/db.vue:
tables: "Tables"
vacuum: "Vacuum"
vacuum-info: "Tidies up the database. Keeps the data intact and reduces disk usage. This is usually done automatically and periodically."
vacuum-exclamation: "Vacuuming can overload the database for a while, and cause users not to be able to participate in interactions."
admin/views/dashboard.vue: admin/views/dashboard.vue:
dashboard: "Dashboard" dashboard: "Dashboard"
accounts: "Accounts" accounts: "Accounts"
@@ -1238,6 +1283,7 @@ admin/views/instance.vue:
smtp-auth: "Perform SMTP authentication" smtp-auth: "Perform SMTP authentication"
smtp-user: "SMTP User" smtp-user: "SMTP User"
smtp-pass: "SMTP Password" smtp-pass: "SMTP Password"
test-email: "Test"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "Enable ServiceWorker" enable-serviceworker: "Enable ServiceWorker"
serviceworker-info: "Must be enabled for push notifications." serviceworker-info: "Must be enabled for push notifications."
@@ -1693,6 +1739,7 @@ deck/deck.user-column.vue:
activity: "Activity" activity: "Activity"
timeline: "Timeline" timeline: "Timeline"
pinned-notes: "Pinned posts" pinned-notes: "Pinned posts"
pinned-page: "Pinned page"
docs: docs:
edit-this-page-on-github: "Found an error, or do you want to contribute to the documentation?" edit-this-page-on-github: "Found an error, or do you want to contribute to the documentation?"
edit-this-page-on-github-link: "Edit this page at GitHub!" edit-this-page-on-github-link: "Edit this page at GitHub!"
@@ -1727,6 +1774,8 @@ pages:
are-you-sure-delete: "Do you want to delete this page?" are-you-sure-delete: "Do you want to delete this page?"
page-deleted: "The page has been deleted" page-deleted: "The page has been deleted"
edit-this-page: "Edit this page" edit-this-page: "Edit this page"
pin-this-page: "Pin to your profile"
unpin-this-page: "Unpin"
view-source: "View Source" view-source: "View Source"
view-page: "View page" view-page: "View page"
like: "Like" like: "Like"
@@ -1745,6 +1794,7 @@ pages:
url: "Page URL" url: "Page URL"
summary: "Summary of page" summary: "Summary of page"
align-center: "Center align" align-center: "Center align"
hide-title-when-pinned: "Hide page title when pinned to profile"
font: "Font" font: "Font"
fontSerif: "Serif" fontSerif: "Serif"
fontSansSerif: "Sans Serif" fontSansSerif: "Sans Serif"
@@ -1798,12 +1848,19 @@ pages:
inc: "Increase number" inc: "Increase number"
_button: _button:
text: "Title" text: "Title"
colored: "Color"
action: "Operation when the button pressed" action: "Operation when the button pressed"
_action: _action:
dialog: "Show a dialog" dialog: "Show a dialog"
_dialog: _dialog:
content: "Content" content: "Content"
resetRandom: "Reset a random number" resetRandom: "Reset a random number"
pushEvent: "Send an event"
_pushEvent:
event: "Name of the event"
message: "Message to display when pressed"
variable: "Variable to send"
no-variable: "None"
script: script:
categories: categories:
flow: "Control" flow: "Control"
@@ -1857,8 +1914,8 @@ pages:
_divide: _divide:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
remind: "÷ Remaindering" mod: "÷ Remaindering"
_remind: _mod:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
eq: "A and B are equal" eq: "A and B are equal"
@@ -1941,6 +1998,9 @@ pages:
_pick: _pick:
arg1: "Lists" arg1: "Lists"
arg2: "Position" arg2: "Position"
listLen: "Get length of list"
_listLen:
arg1: "Lists"
number: "Number" number: "Number"
stringToNumber: "Text to number" stringToNumber: "Text to number"
_stringToNumber: _stringToNumber:

View File

@@ -458,6 +458,8 @@ common/views/components/emoji-picker.vue:
objects: "Objetos" objects: "Objetos"
symbols: "Símbolos" symbols: "Símbolos"
flags: "Países" flags: "Países"
common/views/components/settings/app-type.vue:
info: "Necesitas recargar la página para que los cambios tengan efecto."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "Usuario" username: "Usuario"
password: "Contraseña" password: "Contraseña"
@@ -725,6 +727,7 @@ desktop/views/components/drive.folder.vue:
rename: "Renombrar" rename: "Renombrar"
rename-folder: "Renombrar carpeta" rename-folder: "Renombrar carpeta"
input-new-folder-name: "Escribe el nombre nuevo" input-new-folder-name: "Escribe el nombre nuevo"
else-folders: "Otros"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "Buscar" search: "Buscar"
empty-draghover: "¡Saluda!" empty-draghover: "¡Saluda!"
@@ -939,6 +942,7 @@ admin/views/instance.vue:
smtp-port: "Puerto SMTP" smtp-port: "Puerto SMTP"
smtp-user: "Usuario SMTP" smtp-user: "Usuario SMTP"
smtp-pass: "Contraseña SMTP" smtp-pass: "Contraseña SMTP"
test-email: "Prueba"
admin/views/charts.vue: admin/views/charts.vue:
title: "Gráficos" title: "Gráficos"
per-day: "Por día" per-day: "Por día"
@@ -1090,6 +1094,7 @@ deck:
deck/deck.user-column.vue: deck/deck.user-column.vue:
activity: "Actividad" activity: "Actividad"
pages: pages:
pin-this-page: "Fijar en el perfil"
like: "Me gusta" like: "Me gusta"
blocks: blocks:
post: "Formulario" post: "Formulario"
@@ -1109,5 +1114,7 @@ pages:
arg2: "Listas" arg2: "Listas"
_pick: _pick:
arg1: "Listas" arg1: "Listas"
_listLen:
arg1: "Listas"
types: types:
array: "Listas" array: "Listas"

View File

@@ -12,7 +12,7 @@ common:
rich-contents: "Notes" rich-contents: "Notes"
rich-contents-desc: "Partagez vos idées, les événements et les sujets qui vous tiennent à cœur ainsi que tout autre chose que vous souhaitez partager avec les autres. Si vous le désirez, vous pouvez décorer vos messages en utilisant une syntaxe différente ou en y joignant des sondages et des fichiers, tels que les photos ou les vidéos que vous aimez." rich-contents-desc: "Partagez vos idées, les événements et les sujets qui vous tiennent à cœur ainsi que tout autre chose que vous souhaitez partager avec les autres. Si vous le désirez, vous pouvez décorer vos messages en utilisant une syntaxe différente ou en y joignant des sondages et des fichiers, tels que les photos ou les vidéos que vous aimez."
reaction: "Réactions" reaction: "Réactions"
reaction-desc: "Une manière simple d'exprimer vos émotions. Misskey peut attacher diverses réactions aux publications des autres utilisateurs. Si vous essayez les réactions sur Misskey, vous ne pourrez plus retourner sur une autre plateforme de réseaux sociaux n'offrant que des « J'aime »." reaction-desc: "Une manière simple d'exprimer vos émotions. Misskey peut attacher diverses réactions aux publications des autres utilisateur·rice·s. Si vous essayez les réactions sur Misskey, vous ne pourrez plus retourner sur une autre plateforme de réseaux sociaux n'offrant que des « J'aime »."
ui: "Interface" ui: "Interface"
ui-desc: "Aucune interface graphique ne peut plaire à tout le monde. Par conséquent, Misskey possède une interface utilisateur hautement personnalisable selon vos goûts. Vous pouvez rendre votre page d'accueil originale en modifiant la mise en page de votre fil et en déplaçant les widgets que vous pouvez facilement ajuster pour vous approprier cet espace." ui-desc: "Aucune interface graphique ne peut plaire à tout le monde. Par conséquent, Misskey possède une interface utilisateur hautement personnalisable selon vos goûts. Vous pouvez rendre votre page d'accueil originale en modifiant la mise en page de votre fil et en déplaçant les widgets que vous pouvez facilement ajuster pour vous approprier cet espace."
drive: "Drive" drive: "Drive"
@@ -34,6 +34,7 @@ common:
signup: "S'enregistrer" signup: "S'enregistrer"
signout: "Se déconnecter" signout: "Se déconnecter"
reload-to-apply-the-setting: "Le rechargement de la page est nécessaire pour appliquer ces paramètres. Désirez-vous la recharger maintenant ?" reload-to-apply-the-setting: "Le rechargement de la page est nécessaire pour appliquer ces paramètres. Désirez-vous la recharger maintenant ?"
unfollow-confirm: "Désirez-vous vous désabonner de {name} ?"
got-it: "Jai compris !" got-it: "Jai compris !"
customization-tips: customization-tips:
title: "Conseils de personnalisation" title: "Conseils de personnalisation"
@@ -89,8 +90,8 @@ common:
"write:reactions": "Gérer vos réactions" "write:reactions": "Gérer vos réactions"
"write:votes": "Vote" "write:votes": "Vote"
empty-timeline-info: empty-timeline-info:
follow-users-to-make-your-timeline: "Les utilisateurs suivants afficheront leurs publications sur votre fil." follow-users-to-make-your-timeline: "Les utilisateur·rice·s suivant·e·s afficheront leurs publications sur votre fil."
explore: "Trouver des utilisateurs" explore: "Trouver des utilisateur·rice·s"
post-form: post-form:
attach-location-information: "Joindre des informations de localisation" attach-location-information: "Joindre des informations de localisation"
hide-contents: "Masquer les contenus" hide-contents: "Masquer les contenus"
@@ -148,13 +149,13 @@ common:
public: "Public" public: "Public"
home: "Principal" home: "Principal"
home-desc: "Publier sur le fil principal uniquement" home-desc: "Publier sur le fil principal uniquement"
followers: "Abonnés" followers: "Abonné·e·s"
followers-desc: "Publier à vos abonnés uniquement" followers-desc: "Publier à vos abonné·e·s uniquement"
specified: "Direct" specified: "Direct"
specified-desc: "Publier uniquement aux utilisateurs mentionnés" specified-desc: "Publier uniquement aux utilisateur·rice·s mentionné·e·s"
local-public: "Local (Public)" local-public: "Local (Public)"
local-home: "Accueil (local uniquement)" local-home: "Accueil (local uniquement)"
local-followers: "Local (Abonnés)" local-followers: "Abonné·e·s (Local uniquement)"
note-placeholders: note-placeholders:
a: "Que faites-vous maintenant ?" a: "Que faites-vous maintenant ?"
b: "Quoi de neuf ?" b: "Quoi de neuf ?"
@@ -265,6 +266,7 @@ common:
disable-via-mobile: "Enlever la mention publié via 'mobile'" disable-via-mobile: "Enlever la mention publié via 'mobile'"
load-raw-images: "Afficher les photos jointes dans leur qualité originale" load-raw-images: "Afficher les photos jointes dans leur qualité originale"
load-remote-media: "Afficher les médias depuis le serveur distant" load-remote-media: "Afficher les médias depuis le serveur distant"
sync: "Synchroniser"
search: "Recherche" search: "Recherche"
delete: "Supprimer" delete: "Supprimer"
loading: "Chargement en cours…" loading: "Chargement en cours…"
@@ -314,7 +316,7 @@ common:
version: "Version" version: "Version"
broadcast: "Diffusion" broadcast: "Diffusion"
notifications: "Notifications" notifications: "Notifications"
users: "Utilisateurs recommandés" users: "Utilisateur·rice·s recommandé·e·s"
polls: "Sondages" polls: "Sondages"
post-form: "Champs de publication" post-form: "Champs de publication"
server: "Infos sur le serveur" server: "Infos sur le serveur"
@@ -342,13 +344,13 @@ auth/views/index.vue:
sign-in: "Veuillez vous connecter" sign-in: "Veuillez vous connecter"
common/views/pages/explore.vue: common/views/pages/explore.vue:
pinned-users: "Utilisateur·rice·s épinglé·e·s" pinned-users: "Utilisateur·rice·s épinglé·e·s"
popular-users: "Utilisateurs populaires" popular-users: "Utilisateur·rice·s populaires"
recently-updated-users: "Utilisateurs actifs récemment" recently-updated-users: "Utilisateur·rice·s actif·ve·s récemment"
recently-registered-users: "Les nouveaux inscrits" recently-registered-users: "Les nouveaux inscrits"
popular-tags: "Mots-clés populaires" popular-tags: "Mots-clés populaires"
federated: "Du Fédiverse" federated: "Du Fédiverse"
explore: "Explorer {host}" explore: "Explorer {host}"
users-info: "Actuellement, {users} utilisateurs se sont inscrit ici" users-info: "Actuellement, {users} utilisateur·rice·s se sont inscrit ici"
common/views/components/url-preview.vue: common/views/components/url-preview.vue:
enable-player: "Activer la lecture" enable-player: "Activer la lecture"
disable-player: "Fermer le lecteur" disable-player: "Fermer le lecteur"
@@ -531,8 +533,10 @@ common/views/components/user-menu.vue:
report-abuse-reported: "Transmit à ladministrateur. Merci de votre collaboration." report-abuse-reported: "Transmit à ladministrateur. Merci de votre collaboration."
silence: "Mettre en sourdine" silence: "Mettre en sourdine"
unsilence: "Enlever la sourdine" unsilence: "Enlever la sourdine"
silence-confirm: "Êtes-vous surs de vouloir mettre cet·te utilisateur·rice en sourdine ?"
suspend: "Suspendre" suspend: "Suspendre"
unsuspend: "Ne plus suspendre" unsuspend: "Ne plus suspendre"
suspend-confirm: "Êtes-vous surs de vouloir suspendre cet·te utilisateur·rice ?"
common/views/components/poll.vue: common/views/components/poll.vue:
vote-to: "Voter pour '{}'" vote-to: "Voter pour '{}'"
vote-count: "{} votes" vote-count: "{} votes"
@@ -576,6 +580,8 @@ common/views/components/emoji-picker.vue:
objects: "Objets" objects: "Objets"
symbols: "Symboles" symbols: "Symboles"
flags: "Drapeaux" flags: "Drapeaux"
common/views/components/settings/app-type.vue:
info: "Le rechargement de la page est requis afin d'appliquer les modifications."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "Nom d'utilisateur·rice" username: "Nom d'utilisateur·rice"
password: "Mot de passe" password: "Mot de passe"
@@ -586,6 +592,8 @@ common/views/components/signin.vue:
signin-with-github: "Se connecter avec GitHub" signin-with-github: "Se connecter avec GitHub"
signin-with-discord: "Se connecter avec Discord" signin-with-discord: "Se connecter avec Discord"
login-failed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur et mot de passe sont corrects." login-failed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur et mot de passe sont corrects."
tap-key: "Cliquez sur la clé de sécurité pour vous connecter"
enter-2fa-code: "Entrez votre code de vérification"
common/views/components/signup.vue: common/views/components/signup.vue:
invitation-code: "Code dinvitation" invitation-code: "Code dinvitation"
invitation-info: "Si vous navez pas de code dinvitation, contactez un <a href=\"{}\">administrateur</a>." invitation-info: "Si vous navez pas de code dinvitation, contactez un <a href=\"{}\">administrateur</a>."
@@ -653,13 +661,13 @@ common/views/components/visibility-chooser.vue:
followers: "Abonné·e·s" followers: "Abonné·e·s"
followers-desc: "Publier à vos abonné·e·s uniquement" followers-desc: "Publier à vos abonné·e·s uniquement"
specified: "Direct" specified: "Direct"
specified-desc: "Publier uniquement aux utilisateurs mentionnés" specified-desc: "Publier uniquement aux utilisateur·rice·s mentionné·e·s"
local-public: "Local (Public)" local-public: "Local (Public)"
local-public-desc: "Ne pas publier pour les distants" local-public-desc: "Ne pas publier pour les distants"
local-home: "Accueil (local uniquement)" local-home: "Accueil (local uniquement)"
local-followers: "Local (Abonnés)" local-followers: "Abonné·e·s (Local uniquement)"
common/views/components/trends.vue: common/views/components/trends.vue:
count: "{} utilisateurs mentionnés" count: "{} utilisateur·rice·s mentionné·e·s"
empty: "Aucune tendance" empty: "Aucune tendance"
common/views/components/language-settings.vue: common/views/components/language-settings.vue:
title: "Langue " title: "Langue "
@@ -722,8 +730,10 @@ common/views/components/user-group-editor.vue:
rename: "Renommer le groupe" rename: "Renommer le groupe"
delete: "Supprimer le groupe" delete: "Supprimer le groupe"
transfer: "Transférer de groupe" transfer: "Transférer de groupe"
transfer-are-you-sure: "Êtes vous surs de vouloir ajouter @$2 au groupe $1 ?"
transferred: "Groupe transféré" transferred: "Groupe transféré"
remove-user: "Enlever un utilisateur de ce groupe" remove-user: "Enlever un utilisateur de ce groupe"
delete-are-you-sure: "Désirez-vous vraiment supprimer le groupe $1 ?"
deleted: "Supprimé" deleted: "Supprimé"
invite: "Inviter" invite: "Inviter"
invited: "Invitation envoyée avec succès" invited: "Invitation envoyée avec succès"
@@ -855,7 +865,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "Ne pas marquer comme sensible" unmark-as-sensitive: "Ne pas marquer comme sensible"
copy-url: "Copier lURL" copy-url: "Copier lURL"
download: "Télécharger" download: "Télécharger"
else-files: "Autres..." else-files: "Avancé"
set-as-avatar: "Utiliser en tant qu'avatar" set-as-avatar: "Utiliser en tant qu'avatar"
set-as-banner: "Utiliser en tant que bannière" set-as-banner: "Utiliser en tant que bannière"
open-in-app: "Ouvrir dans l'application" open-in-app: "Ouvrir dans l'application"
@@ -874,6 +884,7 @@ desktop/views/components/drive.folder.vue:
rename: "Renommer" rename: "Renommer"
rename-folder: "Renommer le dossier" rename-folder: "Renommer le dossier"
input-new-folder-name: "Entrer un nouveau nom" input-new-folder-name: "Entrer un nouveau nom"
else-folders: "Avancé"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "Rechercher" search: "Rechercher"
empty-draghover: "Drop Welcome!" empty-draghover: "Drop Welcome!"
@@ -897,7 +908,7 @@ desktop/views/components/media-video.vue:
sensitive: "Le contenu est NSFW" sensitive: "Le contenu est NSFW"
click-to-show: "Cliquer pour afficher" click-to-show: "Cliquer pour afficher"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} abonné·e·s" followers: "Abonné·e·s de {}"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
empty: "Il semble que vous navez pas encore dabonné·e·s." empty: "Il semble que vous navez pas encore dabonné·e·s."
desktop/views/components/following-window.vue: desktop/views/components/following-window.vue:
@@ -979,6 +990,12 @@ desktop/views/components/settings.2fa.vue:
success: "Sauvegarde des paramètres avec succès !" success: "Sauvegarde des paramètres avec succès !"
failed: "Lopération a échoué. Veuillez vous assurer que le jeton a été saisi correctement." failed: "Lopération a échoué. Veuillez vous assurer que le jeton a été saisi correctement."
info: "À partir de maintenant, à chaque fois que vous vous connectez entrez votre mot de passe ainsi que le jeton généré sur votre appareil." info: "À partir de maintenant, à chaque fois que vous vous connectez entrez votre mot de passe ainsi que le jeton généré sur votre appareil."
security-key-header: "Clé de sécurité"
last-used: "Dernière utilisation :"
activate-key: "Cliquez pour activer la clé de sécurité"
security-key-name: "Nom de la clé"
key-unregistered: "La clé a été supprimée"
use-password-less-login: "Utiliser une connexion sans mot de passe"
common/views/components/media-image.vue: common/views/components/media-image.vue:
sensitive: "Contenu sensible" sensitive: "Contenu sensible"
click-to-show: "Cliquer pour afficher" click-to-show: "Cliquer pour afficher"
@@ -1003,6 +1020,7 @@ common/views/components/drive-settings.vue:
max: "Maximale" max: "Maximale"
in-use: "utilisé" in-use: "utilisé"
stats: "Statistiques" stats: "Statistiques"
default-upload-folder-name: "Dossier·s"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "Silencés / Bloqués" mute-and-block: "Silencés / Bloqués"
mute: "Mettre en sourdine" mute: "Mettre en sourdine"
@@ -1088,7 +1106,10 @@ admin/views/index.vue:
abuse: "Abus" abuse: "Abus"
queue: "File dattente" queue: "File dattente"
logs: "Journaux" logs: "Journaux"
db: "Base de données"
back-to-misskey: "Retour vers Misskey" back-to-misskey: "Retour vers Misskey"
admin/views/db.vue:
tables: "Tables"
admin/views/dashboard.vue: admin/views/dashboard.vue:
dashboard: "Tableau de bord" dashboard: "Tableau de bord"
accounts: "Comptes" accounts: "Comptes"
@@ -1212,6 +1233,7 @@ admin/views/instance.vue:
smtp-auth: "Effectuer une authentification SMTP" smtp-auth: "Effectuer une authentification SMTP"
smtp-user: "Utilisateur SMTP" smtp-user: "Utilisateur SMTP"
smtp-pass: "Mot de passe SMTP" smtp-pass: "Mot de passe SMTP"
test-email: "Test"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "Activer ServiceWorker" enable-serviceworker: "Activer ServiceWorker"
serviceworker-info: "Devrait être activé pour les notifications push." serviceworker-info: "Devrait être activé pour les notifications push."
@@ -1224,7 +1246,7 @@ admin/views/charts.vue:
per-hour: "par heure" per-hour: "par heure"
federation: "Fédération" federation: "Fédération"
notes: "Publications" notes: "Publications"
users: "Utilisateurs" users: "Utilisateur·rice·s"
drive: "Lecteur" drive: "Lecteur"
network: "Réseau" network: "Réseau"
charts: charts:
@@ -1234,8 +1256,8 @@ admin/views/charts.vue:
local-notes: "Nombre des publications : augmentation/diminution (Local)" local-notes: "Nombre des publications : augmentation/diminution (Local)"
remote-notes: "Nombre de publications : augmentation/diminution (distants)" remote-notes: "Nombre de publications : augmentation/diminution (distants)"
notes-total: "Total des notes" notes-total: "Total des notes"
users: "Nombre dutilisateurs : augmentation/diminution" users: "Nombre dutilisateur·rice·s : augmentation/diminution"
users-total: "Nombre total des utilisateurs" users-total: "Nombre total des utilisateur·rice·s"
active-users: "Utilisateur·rice·s actif·ve·s" active-users: "Utilisateur·rice·s actif·ve·s"
drive: "Capacité utilisée comme stockage : augmentation/diminution" drive: "Capacité utilisée comme stockage : augmentation/diminution"
drive-total: "Utilisation totale du lecteur" drive-total: "Utilisation totale du lecteur"
@@ -1266,6 +1288,7 @@ admin/views/drive.vue:
unmark-as-sensitive: "Ne pas marquer comme sensible" unmark-as-sensitive: "Ne pas marquer comme sensible"
marked-as-sensitive: "Marqué comme sensible" marked-as-sensitive: "Marqué comme sensible"
unmarked-as-sensitive: "Marqué comme non sensible" unmarked-as-sensitive: "Marqué comme non sensible"
clean-remote-files: "Nettoyer le cache des fichiers distants"
clean-up: "Nettoyage" clean-up: "Nettoyage"
admin/views/users.vue: admin/views/users.vue:
operation: "Actions" operation: "Actions"
@@ -1287,6 +1310,7 @@ admin/views/users.vue:
update-remote-user: "Mettre à jour les informations de lutilisateur·rice distant·e" update-remote-user: "Mettre à jour les informations de lutilisateur·rice distant·e"
remote-user-updated: "Les informations de lutilisateur·rice distant·e ont étés mis à jour" remote-user-updated: "Les informations de lutilisateur·rice distant·e ont étés mis à jour"
delete-all-files: "Supprimer tous les fichiers" delete-all-files: "Supprimer tous les fichiers"
delete-all-files-confirm: "Êtes vous surs de vouloir supprimer tous les fichiers ?"
users: users:
title: "Utilisateur·rice·s" title: "Utilisateur·rice·s"
sort: sort:
@@ -1374,7 +1398,7 @@ admin/views/federation.vue:
lastCommunicatedAtAsc: "La date et l'heure des interactions plus anciennes" lastCommunicatedAtAsc: "La date et l'heure des interactions plus anciennes"
lastCommunicatedAtDesc: "La date et l'heure des nouvelles interactions" lastCommunicatedAtDesc: "La date et l'heure des nouvelles interactions"
notesDesc: "Description des notes" notesDesc: "Description des notes"
usersAsc: "Peu d'abonnés" usersAsc: "Peu d'abonné·e·s"
followingAsc: "Les moins suivies" followingAsc: "Les moins suivies"
followingDesc: "Ayant le plus d'abonné·e·s" followingDesc: "Ayant le plus d'abonné·e·s"
followersAsc: "Ayant le moins d'abonné·e·s" followersAsc: "Ayant le moins d'abonné·e·s"
@@ -1389,7 +1413,7 @@ admin/views/federation.vue:
charts: "Graphs" charts: "Graphs"
chart-srcs: chart-srcs:
requests: "Requêtes" requests: "Requêtes"
users: "Nombre dutilisateurs·trices : augmentation/diminution" users: "Nombre dutilisateur·trice·s : augmentation/diminution"
users-total: "Nombre total des utilisateur·rice·s" users-total: "Nombre total des utilisateur·rice·s"
notes: "Augmentation/diminution du nombre des notes" notes: "Augmentation/diminution du nombre des notes"
notes-total: "Nombre total des notes" notes-total: "Nombre total des notes"
@@ -1431,7 +1455,7 @@ desktop/views/pages/user-list.users.vue:
desktop/views/pages/user/user.followers-you-know.vue: desktop/views/pages/user/user.followers-you-know.vue:
title: "Abonné·e·s que vous connaissez" title: "Abonné·e·s que vous connaissez"
loading: "Chargement en cours" loading: "Chargement en cours"
no-users: "Aucun abonné connu" no-users: "Aucun·e abonné·e connu·e"
desktop/views/pages/user/user.friends.vue: desktop/views/pages/user/user.friends.vue:
title: "Mentions fréquentes" title: "Mentions fréquentes"
loading: "Chargement en cours" loading: "Chargement en cours"
@@ -1646,7 +1670,7 @@ deck/deck.user-column.vue:
follows-you: "Vous suit" follows-you: "Vous suit"
posts: "Notes" posts: "Notes"
following: "Suit" following: "Suit"
followers: "Abonnés" followers: "Abonné·e·s"
images: "Images" images: "Images"
activity: "Activité" activity: "Activité"
timeline: "Fil dactualité" timeline: "Fil dactualité"
@@ -1685,9 +1709,12 @@ pages:
are-you-sure-delete: "Confirmez-vous la suppression de cette page ?" are-you-sure-delete: "Confirmez-vous la suppression de cette page ?"
page-deleted: "La page a bien été supprimée." page-deleted: "La page a bien été supprimée."
edit-this-page: "Éditer cette page" edit-this-page: "Éditer cette page"
pin-this-page: "Épingler sur votre profil"
unpin-this-page: "Désépingler"
view-source: "Afficher la source" view-source: "Afficher la source"
view-page: "Afficher la page" view-page: "Afficher la page"
like: "Bien" like: "Bien"
liked-pages: "Pages favorites"
my-pages: "Mes pages" my-pages: "Mes pages"
inspector: "Inspecteur" inspector: "Inspecteur"
content: "Bloc de page" content: "Bloc de page"
@@ -1697,6 +1724,7 @@ pages:
url: "URL de page" url: "URL de page"
summary: "Résumé de page" summary: "Résumé de page"
align-center: "Centrée" align-center: "Centrée"
hide-title-when-pinned: "Masquer le titre de la page lorsque celle-ci est épinglée au profil"
font: "Police de caractères" font: "Police de caractères"
fontSerif: "Serif" fontSerif: "Serif"
fontSansSerif: "Sans Serif" fontSansSerif: "Sans Serif"
@@ -1749,12 +1777,19 @@ pages:
inc: "Augmenter le chiffre" inc: "Augmenter le chiffre"
_button: _button:
text: "Titre" text: "Titre"
colored: "Couleur"
action: "L'opération lorsque le bouton sera pressé" action: "L'opération lorsque le bouton sera pressé"
_action: _action:
dialog: "Afficher une fenêtre de dialogue" dialog: "Afficher une fenêtre de dialogue"
_dialog: _dialog:
content: "Contenu" content: "Contenu"
resetRandom: "Réinitialiser le nombre aléatoire" resetRandom: "Réinitialiser le nombre aléatoire"
pushEvent: "Envoyer un évènement"
_pushEvent:
event: "Nom de l'évènement"
message: "Message à afficher lorsque appuyé"
variable: "Variable à envoyer"
no-variable: "Aucune"
script: script:
categories: categories:
flow: "Contrôle" flow: "Contrôle"
@@ -1801,7 +1836,7 @@ pages:
_divide: _divide:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
_remind: _mod:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
eq: "A et B sont équivalents" eq: "A et B sont équivalents"
@@ -1873,6 +1908,8 @@ pages:
_pick: _pick:
arg1: "Listes" arg1: "Listes"
arg2: "Position" arg2: "Position"
_listLen:
arg1: "Listes"
number: "Numérique" number: "Numérique"
stringToNumber: "Chaîne en chiffres" stringToNumber: "Chaîne en chiffres"
_stringToNumber: _stringToNumber:

View File

@@ -36,6 +36,7 @@ common:
signout: "ログアウト" signout: "ログアウト"
reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?" reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?"
fetching-as-ap-object: "連合に照会中" fetching-as-ap-object: "連合に照会中"
unfollow-confirm: "{name}さんをフォロー解除しますか?"
got-it: "わかった" got-it: "わかった"
customization-tips: customization-tips:
@@ -128,6 +129,7 @@ common:
add-visible-user: "ユーザーを追加" add-visible-user: "ユーザーを追加"
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
username-prompt: "ユーザー名を入力してください" username-prompt: "ユーザー名を入力してください"
enter-file-name: "ファイル名を編集"
weekday-short: weekday-short:
sunday: "日" sunday: "日"
@@ -200,6 +202,11 @@ common:
remember-note-visibility: "投稿の公開範囲を記憶する" remember-note-visibility: "投稿の公開範囲を記憶する"
web-search-engine: "ウェブ検索エンジン" web-search-engine: "ウェブ検索エンジン"
web-search-engine-desc: "例: https://www.google.com/?#q={{query}}" web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
paste: "ペースト"
pasted-file-name: "ペーストされたファイル名のテンプレート"
pasted-file-name-desc: "例: \"yyyy-MM-dd HH-mm-ss [{{number}}]\" → \"2018-03-20 21-30-24 1\""
paste-dialog: "ペースト時にファイル名を編集"
paste-dialog-desc: "ペースト時にファイル名を編集するダイアログを表示するようにします。"
keep-cw: "CW保持" keep-cw: "CW保持"
keep-cw-desc: "投稿にリプライする際、リプライ元の投稿にCWが設定されていたとき、デフォルトで同じCWを設定するようにします。" keep-cw-desc: "投稿にリプライする際、リプライ元の投稿にCWが設定されていたとき、デフォルトで同じCWを設定するようにします。"
i-like-sushi: "私は(プリンよりむしろ)寿司が好き" i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
@@ -282,6 +289,9 @@ common:
disable-via-mobile: "「モバイルからの投稿」フラグを付けない" disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
load-raw-images: "添付された画像を高画質で表示する" load-raw-images: "添付された画像を高画質で表示する"
load-remote-media: "リモートサーバーのメディアを表示する" load-remote-media: "リモートサーバーのメディアを表示する"
sync: "同期"
home-profile: "ホームのプロファイル"
deck-profile: "デッキのプロファイル"
search: "検索" search: "検索"
delete: "削除" delete: "削除"
@@ -558,6 +568,7 @@ common/views/components/note-menu.vue:
delete: "削除" delete: "削除"
delete-confirm: "この投稿を削除しますか?" delete-confirm: "この投稿を削除しますか?"
remote: "投稿元で見る" remote: "投稿元で見る"
pin-limit-exceeded: "これ以上ピン留めできません。"
common/views/components/user-menu.vue: common/views/components/user-menu.vue:
mention: "メンション" mention: "メンション"
@@ -632,6 +643,15 @@ common/views/components/emoji-picker.vue:
symbols: "記号" symbols: "記号"
flags: "旗" flags: "旗"
common/views/components/settings/app-type.vue:
title: "モード"
intro: "デスクトップ版とモバイル版のどちらを使うかを指定できます。"
choices:
auto: "自動で選択"
desktop: "デスクトップ版に固定"
mobile: "モバイル版に固定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/signin.vue: common/views/components/signin.vue:
username: "ユーザー名" username: "ユーザー名"
password: "パスワード" password: "パスワード"
@@ -642,6 +662,8 @@ common/views/components/signin.vue:
signin-with-github: "GitHubでログイン" signin-with-github: "GitHubでログイン"
signin-with-discord: "Discordでログイン" signin-with-discord: "Discordでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。" login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
tap-key: "セキュリティキーをクリックしてログイン"
enter-2fa-code: "認証コードを入力してください"
common/views/components/signup.vue: common/views/components/signup.vue:
invitation-code: "招待コード" invitation-code: "招待コード"
@@ -951,7 +973,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "閲覧注意を解除" unmark-as-sensitive: "閲覧注意を解除"
copy-url: "URLをコピー" copy-url: "URLをコピー"
download: "ダウンロード" download: "ダウンロード"
else-files: "その他..." else-files: "その他"
set-as-avatar: "アイコンに設定" set-as-avatar: "アイコンに設定"
set-as-banner: "バナーに設定" set-as-banner: "バナーに設定"
open-in-app: "アプリで開く" open-in-app: "アプリで開く"
@@ -962,15 +984,20 @@ desktop/views/components/drive.file.vue:
copied-url-to-clipboard: "URLをクリップボードにコピーしました" copied-url-to-clipboard: "URLをクリップボードにコピーしました"
desktop/views/components/drive.folder.vue: desktop/views/components/drive.folder.vue:
upload-folder: "既定アップロード先"
unable-to-process: "操作を完了できません" unable-to-process: "操作を完了できません"
circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。" circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
unhandled-error: "不明なエラー" unhandled-error: "不明なエラー"
unable-to-delete: "削除できません"
has-child-files-or-folders: "このフォルダは空でないため、削除できません。"
contextmenu: contextmenu:
move-to-this-folder: "このフォルダへ移動" move-to-this-folder: "このフォルダへ移動"
show-in-new-window: "新しいウィンドウで表示" show-in-new-window: "新しいウィンドウで表示"
rename: "名前を変更" rename: "名前を変更"
rename-folder: "フォルダ名の変更" rename-folder: "フォルダ名の変更"
input-new-folder-name: "新しいフォルダ名を入力してください" input-new-folder-name: "新しいフォルダ名を入力してください"
else-folders: "その他"
set-as-upload-folder: "既定アップロード先に設定"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "検索" search: "検索"
@@ -1096,6 +1123,16 @@ desktop/views/components/settings.2fa.vue:
success: "設定が完了しました!" success: "設定が完了しました!"
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
totp-header: "認証アプリ"
security-key-header: "セキュリティキー"
security-key: "セキュリティを強化するために、FIDO2をサポートするハードウェアセキュリティキーを使用してアカウントにログインできます。 サインインの際は、登録されたセキュリティキーまたは認証アプリが必要になります。"
last-used: "最後の使用:"
activate-key: "クリックしてセキュリティキーをアクティベートしてください"
security-key-name: "キー名"
register-security-key: "キーの登録を完了"
something-went-wrong: "わー! キーを登録する際に問題が発生しました:"
key-unregistered: "キーが削除されました"
use-password-less-login: "パスワードなしのログインを使用"
common/views/components/media-image.vue: common/views/components/media-image.vue:
sensitive: "閲覧注意" sensitive: "閲覧注意"
@@ -1124,6 +1161,9 @@ common/views/components/drive-settings.vue:
max: "容量" max: "容量"
in-use: "使用中" in-use: "使用中"
stats: "統計" stats: "統計"
default-upload-folder: "既定のアップロード先フォルダ"
default-upload-folder-name: "フォルダ"
change-default-upload-folder: "フォルダを変更"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "ミュートとブロック" mute-and-block: "ミュートとブロック"
@@ -1226,8 +1266,15 @@ admin/views/index.vue:
abuse: "スパム報告" abuse: "スパム報告"
queue: "ジョブキュー" queue: "ジョブキュー"
logs: "ログ" logs: "ログ"
db: "データベース"
back-to-misskey: "Misskeyに戻る" back-to-misskey: "Misskeyに戻る"
admin/views/db.vue:
tables: "テーブル"
vacuum: "バキューム"
vacuum-info: "データベースの掃除を行います。データはそのままで、ディスク使用量を減らします。通常この操作は自動で定期的に行われます。"
vacuum-exclamation: "バキュームを行うと、しばらくの間データベースの負荷が高くなり、ユーザーの操作を受け付けなくなる場合があります。"
admin/views/dashboard.vue: admin/views/dashboard.vue:
dashboard: "ダッシュボード" dashboard: "ダッシュボード"
accounts: "アカウント" accounts: "アカウント"
@@ -1366,6 +1413,7 @@ admin/views/instance.vue:
smtp-auth: "SMTP認証を行う" smtp-auth: "SMTP認証を行う"
smtp-user: "SMTPユーザー" smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード" smtp-pass: "SMTPパスワード"
test-email: "テスト"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする" enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。" serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
@@ -1882,6 +1930,7 @@ deck/deck.user-column.vue:
activity: "アクティビティ" activity: "アクティビティ"
timeline: "タイムライン" timeline: "タイムライン"
pinned-notes: "ピン留めされた投稿" pinned-notes: "ピン留めされた投稿"
pinned-page: "ピン留めされたページ"
docs: docs:
edit-this-page-on-github: "間違いや改善点を見つけましたか?" edit-this-page-on-github: "間違いや改善点を見つけましたか?"
@@ -1921,6 +1970,8 @@ pages:
are-you-sure-delete: "このページを削除しますか?" are-you-sure-delete: "このページを削除しますか?"
page-deleted: "ページを削除しました" page-deleted: "ページを削除しました"
edit-this-page: "このページを編集" edit-this-page: "このページを編集"
pin-this-page: "ピン留め"
unpin-this-page: "ピン留め解除"
view-source: "ソースを表示" view-source: "ソースを表示"
view-page: "ページを見る" view-page: "ページを見る"
like: "いいね" like: "いいね"
@@ -1939,6 +1990,7 @@ pages:
url: "ページURL" url: "ページURL"
summary: "ページの要約" summary: "ページの要約"
align-center: "中央寄せ" align-center: "中央寄せ"
hide-title-when-pinned: "ピン留めされているときにタイトルを非表示"
font: "フォント" font: "フォント"
fontSerif: "セリフ" fontSerif: "セリフ"
fontSansSerif: "サンセリフ" fontSansSerif: "サンセリフ"
@@ -2000,12 +2052,19 @@ pages:
_button: _button:
text: "タイトル" text: "タイトル"
colored: "色付き"
action: "ボタンを押したときの動作" action: "ボタンを押したときの動作"
_action: _action:
dialog: "ダイアログを表示する" dialog: "ダイアログを表示する"
_dialog: _dialog:
content: "内容" content: "内容"
resetRandom: "乱数をリセット" resetRandom: "乱数をリセット"
pushEvent: "イベントを送信させる"
_pushEvent:
event: "イベント名"
message: "押したときに表示するメッセージ"
variable: "送信する変数"
no-variable: "なし"
script: script:
categories: categories:
@@ -2060,8 +2119,8 @@ pages:
_divide: _divide:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
remind: "÷ 割った余り" mod: "÷ 割った余り"
_remind: _mod:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
eq: "AとBが同じ" eq: "AとBが同じ"
@@ -2144,6 +2203,9 @@ pages:
_pick: _pick:
arg1: "リスト" arg1: "リスト"
arg2: "位置" arg2: "位置"
listLen: "リストの長さを取得"
_listLen:
arg1: "リスト"
number: "数値" number: "数値"
stringToNumber: "テキストを数値に" stringToNumber: "テキストを数値に"
_stringToNumber: _stringToNumber:

View File

@@ -363,6 +363,8 @@ common/views/components/emoji-picker.vue:
objects: "物" objects: "物"
symbols: "記号" symbols: "記号"
flags: "旗" flags: "旗"
common/views/components/settings/app-type.vue:
info: "ページもっぺん読み込んだら反映したるで。"
common/views/components/signin.vue: common/views/components/signin.vue:
username: "ユーザー名" username: "ユーザー名"
password: "パスワード" password: "パスワード"
@@ -601,7 +603,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "やっぱ見せたるわ" unmark-as-sensitive: "やっぱ見せたるわ"
copy-url: "URLをコピー" copy-url: "URLをコピー"
download: "ダウンロード" download: "ダウンロード"
else-files: "まだあんで..." else-files: "その他"
set-as-avatar: "アイコンにする" set-as-avatar: "アイコンにする"
set-as-banner: "バナーにする" set-as-banner: "バナーにする"
open-in-app: "アプリで開く" open-in-app: "アプリで開く"
@@ -620,6 +622,7 @@ desktop/views/components/drive.folder.vue:
rename: "名前を変えるで" rename: "名前を変えるで"
rename-folder: "フォルダ名を変えるで" rename-folder: "フォルダ名を変えるで"
input-new-folder-name: "新しいフォルダ名を入力してや" input-new-folder-name: "新しいフォルダ名を入力してや"
else-folders: "その他"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "検索" search: "検索"
empty-draghover: "ドロップするにゃ!お魚以外なら何でもいいにゃ!" empty-draghover: "ドロップするにゃ!お魚以外なら何でもいいにゃ!"
@@ -747,6 +750,7 @@ common/views/components/drive-settings.vue:
max: "容量" max: "容量"
in-use: "使うとる" in-use: "使うとる"
stats: "統計" stats: "統計"
default-upload-folder-name: "フォルダ"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "ミュートとブロック" mute-and-block: "ミュートとブロック"
mute: "ミュート" mute: "ミュート"
@@ -1234,6 +1238,8 @@ dev/views/new-app.vue:
authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな" authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな"
authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。" authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。"
pages: pages:
pin-this-page: "ピン留め"
unpin-this-page: "ピン留めやめる"
like: "ええやん" like: "ええやん"
blocks: blocks:
image: "画像" image: "画像"
@@ -1254,5 +1260,7 @@ pages:
arg2: "リスト" arg2: "リスト"
_pick: _pick:
arg1: "リスト" arg1: "リスト"
_listLen:
arg1: "リスト"
types: types:
array: "リスト" array: "リスト"

View File

@@ -35,6 +35,7 @@ common:
signout: "로그아웃" signout: "로그아웃"
reload-to-apply-the-setting: "이 설정을 적용하려면 페이지를 새로고침해야 합니다. 바로 새로고침하시겠습니까?" reload-to-apply-the-setting: "이 설정을 적용하려면 페이지를 새로고침해야 합니다. 바로 새로고침하시겠습니까?"
fetching-as-ap-object: "연합에서 조회 중" fetching-as-ap-object: "연합에서 조회 중"
unfollow-confirm: "{name} 님을 팔로우 해제하시겠습니까?"
got-it: "알겠습니다" got-it: "알겠습니다"
customization-tips: customization-tips:
title: "커스터마이징 도움말" title: "커스터마이징 도움말"
@@ -116,12 +117,13 @@ common:
local-only-message: "이 글은 로컬에만 공개되어 있습니다" local-only-message: "이 글은 로컬에만 공개되어 있습니다"
click-to-tagging: "클릭하여 태그 넣기" click-to-tagging: "클릭하여 태그 넣기"
visibility: "공개 범위" visibility: "공개 범위"
geolocation-alert: "사용 중 장치에서는 위치 정보를 사용할 수 없습니다" geolocation-alert: "사용 중이신 장치에서는 위치 정보를 사용할 수 없습니다"
error: "오류" error: "오류"
enter-username: "사용자명을 입력해주세요" enter-username: "사용자명을 입력해주세요"
add-visible-user: "사용자 추가" add-visible-user: "사용자 추가"
cw-placeholder: "내용에 대한 주석 (옵션)" cw-placeholder: "내용에 대한 주석 (옵션)"
username-prompt: "사용자명을 입력해주세요" username-prompt: "사용자명을 입력해주세요"
enter-file-name: "파일 이름 수정"
weekday-short: weekday-short:
sunday: "일" sunday: "일"
monday: "월" monday: "월"
@@ -188,6 +190,11 @@ common:
remember-note-visibility: "글의 공개 범위를 기억하기" remember-note-visibility: "글의 공개 범위를 기억하기"
web-search-engine: "웹 검색엔진" web-search-engine: "웹 검색엔진"
web-search-engine-desc: "예: https://www.google.com/?#q={{query}}" web-search-engine-desc: "예: https://www.google.com/?#q={{query}}"
paste: "붙여넣기"
pasted-file-name: "붙여넣은 파일의 이름 템플릿"
pasted-file-name-desc: "예시: \"yyyy-MM-dd HH-mm-ss [{{number}}]\" → \"2018-03-20 21-30-24 1\""
paste-dialog: "붙여넣기 시 파일 이름을 편집"
paste-dialog-desc: "붙여넣기 시 파일 이름을 편집할 수 있도록 대화 상자를 표시합니다."
keep-cw: "CW 유지" keep-cw: "CW 유지"
keep-cw-desc: "글에 답글을 달 때, 답글할 글에 CW가 설정되어 있는 경우 기본값으로 동일한 CW를 설정하도록 합니다." keep-cw-desc: "글에 답글을 달 때, 답글할 글에 CW가 설정되어 있는 경우 기본값으로 동일한 CW를 설정하도록 합니다."
i-like-sushi: "저는 (푸딩보다 차라리) 초밥이 좋아요" i-like-sushi: "저는 (푸딩보다 차라리) 초밥이 좋아요"
@@ -270,6 +277,9 @@ common:
disable-via-mobile: "작성하는 글에 \"모바일에서 작성함\" 을 붙이지 않음" disable-via-mobile: "작성하는 글에 \"모바일에서 작성함\" 을 붙이지 않음"
load-raw-images: "첨부 이미지를 고품질로 표시" load-raw-images: "첨부 이미지를 고품질로 표시"
load-remote-media: "원격 서버의 미디어를 표시" load-remote-media: "원격 서버의 미디어를 표시"
sync: "동기화"
home-profile: "홈 프로필"
deck-profile: "덱 프로필"
search: "검색" search: "검색"
delete: "삭제" delete: "삭제"
loading: "로드 중" loading: "로드 중"
@@ -286,7 +296,7 @@ common:
is-remote-user: "이 사용자 정보는 정확하지 않을 수 있습니다." is-remote-user: "이 사용자 정보는 정확하지 않을 수 있습니다."
is-remote-post: "이 글 정보는 복사본입니다." is-remote-post: "이 글 정보는 복사본입니다."
view-on-remote: "정확한 정보 보기" view-on-remote: "정확한 정보 보기"
renoted-by: "{user}이(가) 리노트" renoted-by: "{user}이 리노트"
no-notes: "글이 없습니다" no-notes: "글이 없습니다"
turn-on-darkmode: "어둠에 삼켜져라" turn-on-darkmode: "어둠에 삼켜져라"
turn-off-darkmode: "빛이 있으라" turn-off-darkmode: "빛이 있으라"
@@ -520,6 +530,7 @@ common/views/components/note-menu.vue:
delete: "삭제" delete: "삭제"
delete-confirm: "이 글을 삭제하시겠습니까?" delete-confirm: "이 글을 삭제하시겠습니까?"
remote: "글 원본 보기" remote: "글 원본 보기"
pin-limit-exceeded: "더 이상 고정할 수 없습니다."
common/views/components/user-menu.vue: common/views/components/user-menu.vue:
mention: "멘션" mention: "멘션"
mute: "뮤트" mute: "뮤트"
@@ -588,6 +599,14 @@ common/views/components/emoji-picker.vue:
objects: "사물" objects: "사물"
symbols: "기호" symbols: "기호"
flags: "깃발" flags: "깃발"
common/views/components/settings/app-type.vue:
title: "모드"
intro: "데스크톱과 모바일 중 어떤 레이아웃을 사용할 지 지정할 수 있습니다."
choices:
auto: "자동으로 선택"
desktop: "데스크톱 레이아웃으로 고정"
mobile: "모바일 레이아웃으로 고정"
info: "변경사항은 페이지를 새로고침한 뒤에 반영됩니다."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "사용자명" username: "사용자명"
password: "비밀번호" password: "비밀번호"
@@ -598,6 +617,8 @@ common/views/components/signin.vue:
signin-with-github: "GitHub으로 로그인" signin-with-github: "GitHub으로 로그인"
signin-with-discord: "Discord로 로그인" signin-with-discord: "Discord로 로그인"
login-failed: "로그인할 수 없습니다. 사용자명과 비밀번호를 확인하여 주십시오." login-failed: "로그인할 수 없습니다. 사용자명과 비밀번호를 확인하여 주십시오."
tap-key: "보안 키를 클릭하여 로그인"
enter-2fa-code: "인증 코드를 입력하여 주십시오"
common/views/components/signup.vue: common/views/components/signup.vue:
invitation-code: "초대 코드" invitation-code: "초대 코드"
invitation-info: "초대 코드가 없으신 분은 <a href=\"{}\">관리자</a>에게 연락하시기 바랍니다." invitation-info: "초대 코드가 없으신 분은 <a href=\"{}\">관리자</a>에게 연락하시기 바랍니다."
@@ -870,7 +891,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "열람주의 해제" unmark-as-sensitive: "열람주의 해제"
copy-url: "URL 복사" copy-url: "URL 복사"
download: "다운로드" download: "다운로드"
else-files: "기타..." else-files: "기타"
set-as-avatar: "아이콘으로 설정" set-as-avatar: "아이콘으로 설정"
set-as-banner: "배너로 설정" set-as-banner: "배너로 설정"
open-in-app: "앱에서 열기" open-in-app: "앱에서 열기"
@@ -880,15 +901,20 @@ desktop/views/components/drive.file.vue:
copied: "복사 완료" copied: "복사 완료"
copied-url-to-clipboard: "URL을 클립보드에 복사하였습니다" copied-url-to-clipboard: "URL을 클립보드에 복사하였습니다"
desktop/views/components/drive.folder.vue: desktop/views/components/drive.folder.vue:
upload-folder: "기본 업로드 위치"
unable-to-process: "작업을 완료할 수 없습니다" unable-to-process: "작업을 완료할 수 없습니다"
circular-reference-detected: "대상 폴더가 이동할 폴더의 하위 폴더입니다." circular-reference-detected: "대상 폴더가 이동할 폴더의 하위 폴더입니다."
unhandled-error: "알 수 없는 오류" unhandled-error: "알 수 없는 오류"
unable-to-delete: "삭제할 수 없습니다"
has-child-files-or-folders: "이 폴더는 비어있지 않기 때문에 삭제할 수 없습니다."
contextmenu: contextmenu:
move-to-this-folder: "이 폴더로 이동" move-to-this-folder: "이 폴더로 이동"
show-in-new-window: "새 창으로 보기" show-in-new-window: "새 창으로 보기"
rename: "이름 변경" rename: "이름 변경"
rename-folder: "폴더 이름 변경" rename-folder: "폴더 이름 변경"
input-new-folder-name: "새 폴더 이름을 입력하여 주십시오" input-new-folder-name: "새 폴더 이름을 입력하여 주십시오"
else-folders: "기타"
set-as-upload-folder: "기본 업로드 위치로 설정"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "검색" search: "검색"
empty-draghover: "끌어놓으신 거 맞나요? 괜찮아요, 저는 귀여우니까요" empty-draghover: "끌어놓으신 거 맞나요? 괜찮아요, 저는 귀여우니까요"
@@ -994,6 +1020,16 @@ desktop/views/components/settings.2fa.vue:
success: "설정이 완료되었습니다!" success: "설정이 완료되었습니다!"
failed: "설정에 실패했습니다. 토큰이 잘못되었는지 확인해주십시오." failed: "설정에 실패했습니다. 토큰이 잘못되었는지 확인해주십시오."
info: "다음 로그인부터는 이와 동일하게 비밀번호에 더해 장치에 표시된 토큰을 입력합니다." info: "다음 로그인부터는 이와 동일하게 비밀번호에 더해 장치에 표시된 토큰을 입력합니다."
totp-header: "인증 앱"
security-key-header: "보안 키"
security-key: "보안을 강화하려면 FIDO2를 지원하는 하드웨어 보안 키를 사용하여 계정에 로그인할 수 있습니다. 로그인 시 등록하였던 보안 키 또는 인증 앱이 필요하게 됩니다."
last-used: "마지막 사용:"
activate-key: "클릭하여 보안 키를 활성화하여 주십시오"
security-key-name: "키 이름"
register-security-key: "키 등록 완료"
something-went-wrong: "으악! 키를 등록하는 도중 문제가 발생하였습니다:"
key-unregistered: "키가 등록되어 있지 않습니다"
use-password-less-login: "비밀번호 없는 로그인 사용"
common/views/components/media-image.vue: common/views/components/media-image.vue:
sensitive: "열람주의" sensitive: "열람주의"
click-to-show: "클릭하여 보기" click-to-show: "클릭하여 보기"
@@ -1018,6 +1054,9 @@ common/views/components/drive-settings.vue:
max: "최대 용량" max: "최대 용량"
in-use: "사용중" in-use: "사용중"
stats: "통계" stats: "통계"
default-upload-folder: "기본 업로드 폴더 위치"
default-upload-folder-name: "폴더"
change-default-upload-folder: "폴더 변경"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "뮤트 및 차단" mute-and-block: "뮤트 및 차단"
mute: "뮤트" mute: "뮤트"
@@ -1103,7 +1142,13 @@ admin/views/index.vue:
abuse: "스팸 신고" abuse: "스팸 신고"
queue: "작업 대기열" queue: "작업 대기열"
logs: "로그" logs: "로그"
db: "데이터베이스"
back-to-misskey: "Misskey로 돌아가기" back-to-misskey: "Misskey로 돌아가기"
admin/views/db.vue:
tables: "테이블"
vacuum: "청소"
vacuum-info: "데이터베이스를 청소합니다. 데이터는 그대로인 채로 데이터의 사용량을 줄입니다. 일반적으로 이 작업은 자동으로 정기적으로 수행됩니다."
vacuum-exclamation: "청소를 수행하면 한동안 데이터베이스의 부하가 높아져 사용자 조작을 처리하지 못 할 수 있습니다."
admin/views/dashboard.vue: admin/views/dashboard.vue:
dashboard: "대시보드" dashboard: "대시보드"
accounts: "계정" accounts: "계정"
@@ -1126,7 +1171,7 @@ admin/views/queue.vue:
states: states:
active: "처리중" active: "처리중"
delayed: "지연됨" delayed: "지연됨"
waiting: "대기열에 들어감" waiting: "대기열에 있음"
result-is-truncated: "결과는 생략되었습니다" result-is-truncated: "결과는 생략되었습니다"
other-queues: "기타 큐" other-queues: "기타 큐"
admin/views/logs.vue: admin/views/logs.vue:
@@ -1238,6 +1283,7 @@ admin/views/instance.vue:
smtp-auth: "SMTP 인증 수행" smtp-auth: "SMTP 인증 수행"
smtp-user: "SMTP 사용자" smtp-user: "SMTP 사용자"
smtp-pass: "SMTP 비밀번호" smtp-pass: "SMTP 비밀번호"
test-email: "테스트"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorker 사용" enable-serviceworker: "ServiceWorker 사용"
serviceworker-info: "푸시알림을 수행하려면 사용해야 합니다." serviceworker-info: "푸시알림을 수행하려면 사용해야 합니다."
@@ -1693,6 +1739,7 @@ deck/deck.user-column.vue:
activity: "활동" activity: "활동"
timeline: "타임라인" timeline: "타임라인"
pinned-notes: "고정해놓은 글" pinned-notes: "고정해놓은 글"
pinned-page: "고정해놓은 페이지"
docs: docs:
edit-this-page-on-github: "틀린 점이나 개선할 점을 찾으셨나요?" edit-this-page-on-github: "틀린 점이나 개선할 점을 찾으셨나요?"
edit-this-page-on-github-link: "이 페이지를 GitHub에서 편집" edit-this-page-on-github-link: "이 페이지를 GitHub에서 편집"
@@ -1727,6 +1774,8 @@ pages:
are-you-sure-delete: "이 페이지를 삭제하시겠습니까?" are-you-sure-delete: "이 페이지를 삭제하시겠습니까?"
page-deleted: "페이지가 삭제되었습니다" page-deleted: "페이지가 삭제되었습니다"
edit-this-page: "이 페이지를 편집" edit-this-page: "이 페이지를 편집"
pin-this-page: "프로필에 고정"
unpin-this-page: "프로필에서 고정 해제"
view-source: "소스 보기" view-source: "소스 보기"
view-page: "페이지 보기" view-page: "페이지 보기"
like: "좋아요" like: "좋아요"
@@ -1745,6 +1794,7 @@ pages:
url: "페이지 URL" url: "페이지 URL"
summary: "페이지 요약" summary: "페이지 요약"
align-center: "가운데 정렬" align-center: "가운데 정렬"
hide-title-when-pinned: "프로필에 고정해놓은 경우 타이틀을 표시하지 않음"
font: "글꼴" font: "글꼴"
fontSerif: "세리프" fontSerif: "세리프"
fontSansSerif: "산 세리프" fontSansSerif: "산 세리프"
@@ -1798,12 +1848,19 @@ pages:
inc: "증가치" inc: "증가치"
_button: _button:
text: "제목" text: "제목"
colored: "색상"
action: "버튼을 눌렀을 때의 동작" action: "버튼을 눌렀을 때의 동작"
_action: _action:
dialog: "대화상자를 표시" dialog: "대화상자를 표시"
_dialog: _dialog:
content: "내용" content: "내용"
resetRandom: "난수를 초기화" resetRandom: "난수를 초기화"
pushEvent: "이벤트 보내기"
_pushEvent:
event: "이벤트 이름"
message: "눌렀을 때 표시할 메시지"
variable: "보낼 변수"
no-variable: "없음"
script: script:
categories: categories:
flow: "흐름 제어" flow: "흐름 제어"
@@ -1857,8 +1914,8 @@ pages:
_divide: _divide:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
remind: "÷ 나눈 나머지" mod: "÷ 나눈 나머지"
_remind: _mod:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
eq: "A와 B가 동일" eq: "A와 B가 동일"
@@ -1941,6 +1998,9 @@ pages:
_pick: _pick:
arg1: "리스트" arg1: "리스트"
arg2: "위치" arg2: "위치"
listLen: "리스트의 길이 가져오기"
_listLen:
arg1: "리스트"
number: "수치" number: "수치"
stringToNumber: "텍스트를 수치로" stringToNumber: "텍스트를 수치로"
_stringToNumber: _stringToNumber:

View File

@@ -260,7 +260,6 @@ desktop/views/components/drive.file.vue:
rename: "Naam wijzigen" rename: "Naam wijzigen"
copy-url: "URL kopiëren" copy-url: "URL kopiëren"
download: "Downloaden" download: "Downloaden"
else-files: "Overig"
set-as-avatar: "Instellen als gebruikersafbeelding" set-as-avatar: "Instellen als gebruikersafbeelding"
set-as-banner: "Instellen als omslagfoto" set-as-banner: "Instellen als omslagfoto"
open-in-app: "Openen in app" open-in-app: "Openen in app"
@@ -377,6 +376,7 @@ common/views/components/api-settings.vue:
common/views/components/drive-settings.vue: common/views/components/drive-settings.vue:
in-use: "gebruikt" in-use: "gebruikt"
stats: "Statistieken" stats: "Statistieken"
default-upload-folder-name: "Map(pen)"
desktop/views/components/sub-note-content.vue: desktop/views/components/sub-note-content.vue:
private: "(dit bericht is privé)" private: "(dit bericht is privé)"
poll: "Peilingen" poll: "Peilingen"
@@ -606,6 +606,7 @@ docs:
edit-this-page-on-github: "Heb je een fout ontdekt of wil je bijdragen aan de documentatie? " 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!" edit-this-page-on-github-link: "Bewerk deze pagina op GitHub!"
pages: pages:
pin-this-page: "Vastmaken aan profielpagina"
like: "Leuk" like: "Leuk"
blocks: blocks:
image: "Afbeeldingen" image: "Afbeeldingen"
@@ -623,5 +624,7 @@ pages:
arg2: "Lijsten" arg2: "Lijsten"
_pick: _pick:
arg1: "Lijsten" arg1: "Lijsten"
_listLen:
arg1: "Lijsten"
types: types:
array: "Lijsten" array: "Lijsten"

View File

@@ -286,6 +286,7 @@ common/views/components/api-settings.vue:
common/views/components/drive-settings.vue: common/views/components/drive-settings.vue:
in-use: "brukt" in-use: "brukt"
stats: "Statistikk" stats: "Statistikk"
default-upload-folder-name: "Mappe(r)"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
save: "Lagre" save: "Lagre"
desktop/views/components/settings.tags.vue: desktop/views/components/settings.tags.vue:
@@ -484,6 +485,7 @@ deck/deck.user-column.vue:
followers: "Følgere" followers: "Følgere"
images: "Bilder" images: "Bilder"
pages: pages:
pin-this-page: "Fest til profilen din"
like: "Lik" like: "Lik"
blocks: blocks:
image: "Bilder" image: "Bilder"
@@ -503,5 +505,7 @@ pages:
arg2: "Lister" arg2: "Lister"
_pick: _pick:
arg1: "Lister" arg1: "Lister"
_listLen:
arg1: "Lister"
types: types:
array: "Lister" array: "Lister"

View File

@@ -65,6 +65,7 @@ common:
favorites: "Moje ulubione" favorites: "Moje ulubione"
permissions: permissions:
"read:drive": "Wyświetl dysk" "read:drive": "Wyświetl dysk"
"read:messaging": "Zobacz konwersację"
"write:votes": "Zagłosuj" "write:votes": "Zagłosuj"
empty-timeline-info: empty-timeline-info:
explore: "Poznaj" explore: "Poznaj"
@@ -72,6 +73,7 @@ common:
hide-contents: "Ukryj zawartość" hide-contents: "Ukryj zawartość"
reply-placeholder: "Odpowiedź na ten wpis…" reply-placeholder: "Odpowiedź na ten wpis…"
quote-placeholder: "Zacytuj ten wpis…" quote-placeholder: "Zacytuj ten wpis…"
quote-attached: "Z cytatem"
submit: "Wpis" submit: "Wpis"
reply: "Odpowiedz" reply: "Odpowiedz"
renote: "Udostępnij" renote: "Udostępnij"
@@ -412,6 +414,8 @@ common/views/components/emoji-picker.vue:
objects: "Rzeczy" objects: "Rzeczy"
symbols: "Symbole" symbols: "Symbole"
flags: "Flagi" flags: "Flagi"
common/views/components/settings/app-type.vue:
info: "Musisz odświeżyć stronę, aby zmiany zostały uwzględnione."
common/views/components/signin.vue: common/views/components/signin.vue:
username: "Nazwa użytkownika" username: "Nazwa użytkownika"
password: "Hasło" password: "Hasło"
@@ -664,6 +668,7 @@ desktop/views/components/drive.folder.vue:
rename: "Zmień nazwę" rename: "Zmień nazwę"
rename-folder: "Zmień nazwę katalogu" rename-folder: "Zmień nazwę katalogu"
input-new-folder-name: "Wprowadź nową nazwę" input-new-folder-name: "Wprowadź nową nazwę"
else-folders: "Inne"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "Szukaj" search: "Szukaj"
empty-draghover: "Przeciągnij tutaj!" empty-draghover: "Przeciągnij tutaj!"
@@ -783,6 +788,7 @@ common/views/components/drive-settings.vue:
max: "Max" max: "Max"
in-use: "użyto" in-use: "użyto"
stats: "Statystyki" stats: "Statystyki"
default-upload-folder-name: "Katalog(i)"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "Wycisz / Zablokuj" mute-and-block: "Wycisz / Zablokuj"
mute: "Wycisz" mute: "Wycisz"
@@ -880,6 +886,7 @@ admin/views/instance.vue:
save: "Zapisz" save: "Zapisz"
saved: "Zapisano" saved: "Zapisano"
email: "Adres e-mail" email: "Adres e-mail"
test-email: "Test"
admin/views/charts.vue: admin/views/charts.vue:
notes: "Wpisy" notes: "Wpisy"
users: "Użytkownicy" users: "Użytkownicy"
@@ -1186,6 +1193,8 @@ dev/views/new-app.vue:
app-name: "Nazwa Aplikacji" app-name: "Nazwa Aplikacji"
authority: "Uprawnienia" authority: "Uprawnienia"
pages: pages:
pin-this-page: "Przypnij do profilu"
unpin-this-page: "Odepnij"
like: "Lubię" like: "Lubię"
title: "Tytuł" title: "Tytuł"
blocks: blocks:
@@ -1219,5 +1228,7 @@ pages:
arg2: "Listy" arg2: "Listy"
_pick: _pick:
arg1: "Listy" arg1: "Listy"
_listLen:
arg1: "Listy"
types: types:
array: "Listy" array: "Listy"

View File

@@ -26,6 +26,14 @@ common:
do-not-copy-paste: "Пожалуйста, не вводите и не вставляйте сюда код. Аккаунту может угрожать опасность." do-not-copy-paste: "Пожалуйста, не вводите и не вставляйте сюда код. Аккаунту может угрожать опасность."
load-more: "Загрузить больше" load-more: "Загрузить больше"
enter-password: "Пожалуйста, введите ваш пароль" enter-password: "Пожалуйста, введите ваш пароль"
2fa: "Двухфакторная аутентификация"
customize-home: "Настройка домашней страницы"
featured-notes: "Рекомендуемые"
dark-mode: "Тёмная тема"
signin: "Войти"
signup: "Регистрация"
signout: "Выйти"
reload-to-apply-the-setting: "Вам необходимо перезагрузить страницу, чтобы применить настройки. Вы хотите перезагрузить сейчас?"
customization-tips: customization-tips:
title: "Советы по настройке" title: "Советы по настройке"
gotit: "Понятно!" gotit: "Понятно!"
@@ -51,7 +59,14 @@ common:
month-and-day: "{day}.{month}" month-and-day: "{day}.{month}"
trash: "Мусорное ведро" trash: "Мусорное ведро"
drive: "Drive" drive: "Drive"
pages: "Страницы"
messaging: "Чат" messaging: "Чат"
timeline: "Лента"
followers: "Подписчики"
favorites: "Избранное"
post-form:
reply: "Ответить"
create-poll: "Создать опрос"
weekday-short: weekday-short:
sunday: "Вс" sunday: "Вс"
monday: "Пн" monday: "Пн"

View File

@@ -270,6 +270,9 @@ common:
disable-via-mobile: "不要将帖子标记为“来自手机”" disable-via-mobile: "不要将帖子标记为“来自手机”"
load-raw-images: "以原始质量显示附加图像" load-raw-images: "以原始质量显示附加图像"
load-remote-media: "显示来自远程服务器的媒体" load-remote-media: "显示来自远程服务器的媒体"
sync: "同步"
home-profile: "定制首页数据"
deck-profile: "定制Deck数据"
search: "搜索" search: "搜索"
delete: "删除" delete: "删除"
loading: "正在加载中" loading: "正在加载中"
@@ -588,6 +591,8 @@ common/views/components/emoji-picker.vue:
objects: "物品" objects: "物品"
symbols: "符号" symbols: "符号"
flags: "旗帜" flags: "旗帜"
common/views/components/settings/app-type.vue:
info: "更改将在刷新页面后生效。"
common/views/components/signin.vue: common/views/components/signin.vue:
username: "用户名" username: "用户名"
password: "密码" password: "密码"
@@ -859,7 +864,7 @@ desktop/views/components/crop-window.vue:
cancel: "取消" cancel: "取消"
ok: "确定" ok: "确定"
desktop/views/components/drive-window.vue: desktop/views/components/drive-window.vue:
used: "使用" used: "使用"
desktop/views/components/drive.file.vue: desktop/views/components/drive.file.vue:
avatar: "头像" avatar: "头像"
banner: "背景" banner: "背景"
@@ -870,7 +875,7 @@ desktop/views/components/drive.file.vue:
unmark-as-sensitive: "取消标记为“敏感”" unmark-as-sensitive: "取消标记为“敏感”"
copy-url: "复制链接" copy-url: "复制链接"
download: "下载" download: "下载"
else-files: "其他..." else-files: "其他"
set-as-avatar: "设置为头像" set-as-avatar: "设置为头像"
set-as-banner: "设置为背景" set-as-banner: "设置为背景"
open-in-app: "在应用程序中打开" open-in-app: "在应用程序中打开"
@@ -889,6 +894,7 @@ desktop/views/components/drive.folder.vue:
rename: "重命名" rename: "重命名"
rename-folder: "重命名文件夹" rename-folder: "重命名文件夹"
input-new-folder-name: "请输入新文件名" input-new-folder-name: "请输入新文件名"
else-folders: "其他"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "搜索" search: "搜索"
empty-draghover: "放在这里!因为你知道我很可爱,对吗?" empty-draghover: "放在这里!因为你知道我很可爱,对吗?"
@@ -1016,8 +1022,9 @@ desktop/views/components/settings.apps.vue:
no-apps: "没有已连接的应用程序" no-apps: "没有已连接的应用程序"
common/views/components/drive-settings.vue: common/views/components/drive-settings.vue:
max: "容量" max: "容量"
in-use: "正在使用" in-use: "使用"
stats: "统计" stats: "统计"
default-upload-folder-name: "文件夹"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "屏蔽/拉黑" mute-and-block: "屏蔽/拉黑"
mute: "屏蔽" mute: "屏蔽"
@@ -1103,7 +1110,10 @@ admin/views/index.vue:
abuse: "举报垃圾信息" abuse: "举报垃圾信息"
queue: "作业队列" queue: "作业队列"
logs: "登录" logs: "登录"
db: "数据库"
back-to-misskey: "返回 Misskey" back-to-misskey: "返回 Misskey"
admin/views/db.vue:
tables: "表格"
admin/views/dashboard.vue: admin/views/dashboard.vue:
dashboard: "Dashboard" dashboard: "Dashboard"
accounts: "账户" accounts: "账户"
@@ -1238,6 +1248,7 @@ admin/views/instance.vue:
smtp-auth: "SMTP身份验证" smtp-auth: "SMTP身份验证"
smtp-user: "SMTP 用户名" smtp-user: "SMTP 用户名"
smtp-pass: "SMTP 密码" smtp-pass: "SMTP 密码"
test-email: "测试"
serviceworker-config: "ServiceWorker" serviceworker-config: "ServiceWorker"
enable-serviceworker: "启用ServiceWorker" enable-serviceworker: "启用ServiceWorker"
serviceworker-info: "您需要启用推送通知" serviceworker-info: "您需要启用推送通知"
@@ -1518,7 +1529,7 @@ desktop/views/widgets/users.vue:
refresh: "更多" refresh: "更多"
no-one: "不是!" no-one: "不是!"
mobile/views/components/drive.vue: mobile/views/components/drive.vue:
used: "使用" used: "使用"
folder-count: "文件夹" folder-count: "文件夹"
count-separator: "" count-separator: ""
file-count: "文件" file-count: "文件"
@@ -1727,6 +1738,8 @@ pages:
are-you-sure-delete: "是否删除此页面?" are-you-sure-delete: "是否删除此页面?"
page-deleted: "该页面已被删除。" page-deleted: "该页面已被删除。"
edit-this-page: "编辑此页面" edit-this-page: "编辑此页面"
pin-this-page: "置顶"
unpin-this-page: "取消置顶"
view-source: "查看源代码" view-source: "查看源代码"
view-page: "查看页面" view-page: "查看页面"
like: "赞" like: "赞"
@@ -1857,8 +1870,8 @@ pages:
_divide: _divide:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
remind: "÷ 取模" mod: "÷ 取模"
_remind: _mod:
arg1: "A" arg1: "A"
arg2: "B" arg2: "B"
eq: "A和B相等" eq: "A和B相等"
@@ -1941,6 +1954,9 @@ pages:
_pick: _pick:
arg1: "列表" arg1: "列表"
arg2: "位置" arg2: "位置"
listLen: "获取列表长度"
_listLen:
arg1: "列表"
number: "数值" number: "数值"
stringToNumber: "文本到数字" stringToNumber: "文本到数字"
_stringToNumber: _stringToNumber:

View File

@@ -0,0 +1,485 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class Init1000000000000 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TYPE "log_level_enum" AS ENUM('error', 'warning', 'info', 'success', 'debug')`);
await queryRunner.query(`CREATE TABLE "log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "domain" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "level" "log_level_enum" NOT NULL, "worker" character varying(8) NOT NULL, "machine" character varying(128) NOT NULL, "message" character varying(1024) NOT NULL, "data" jsonb NOT NULL DEFAULT '{}', CONSTRAINT "PK_350604cbdf991d5930d9e618fbd" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_8e4eb51a35d81b64dda28eed0a" ON "log" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_8cb40cfc8f3c28261e6f887b03" ON "log" ("domain") `);
await queryRunner.query(`CREATE INDEX "IDX_584b536b49e53ac81beb39a177" ON "log" ("level") `);
await queryRunner.query(`CREATE TABLE "drive_folder" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(128) NOT NULL, "userId" character varying(32), "parentId" character varying(32), CONSTRAINT "PK_7a0c089191f5ebdc214e0af808a" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_02878d441ceae15ce060b73daf" ON "drive_folder" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_f4fc06e49c0171c85f1c48060d" ON "drive_folder" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_00ceffb0cdc238b3233294f08f" ON "drive_folder" ("parentId") `);
await queryRunner.query(`CREATE TABLE "drive_file" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32), "userHost" character varying(128), "md5" character varying(32) NOT NULL, "name" character varying(256) NOT NULL, "type" character varying(128) NOT NULL, "size" integer NOT NULL, "comment" character varying(512), "properties" jsonb NOT NULL DEFAULT '{}', "storedInternal" boolean NOT NULL, "url" character varying(512) NOT NULL, "thumbnailUrl" character varying(512), "webpublicUrl" character varying(512), "accessKey" character varying(256), "thumbnailAccessKey" character varying(256), "webpublicAccessKey" character varying(256), "uri" character varying(512), "src" character varying(512), "folderId" character varying(32), "isSensitive" boolean NOT NULL DEFAULT false, "isLink" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_43ddaaaf18c9e68029b7cbb032e" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_c8dfad3b72196dd1d6b5db168a" ON "drive_file" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_860fa6f6c7df5bb887249fba22" ON "drive_file" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_92779627994ac79277f070c91e" ON "drive_file" ("userHost") `);
await queryRunner.query(`CREATE INDEX "IDX_37bb9a1b4585f8a3beb24c62d6" ON "drive_file" ("md5") `);
await queryRunner.query(`CREATE INDEX "IDX_a40b8df8c989d7db937ea27cf6" ON "drive_file" ("type") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d85a184c2540d2deba33daf642" ON "drive_file" ("accessKey") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e74022ce9a074b3866f70e0d27" ON "drive_file" ("thumbnailAccessKey") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_c55b2b7c284d9fef98026fc88e" ON "drive_file" ("webpublicAccessKey") `);
await queryRunner.query(`CREATE INDEX "IDX_e5848eac4940934e23dbc17581" ON "drive_file" ("uri") `);
await queryRunner.query(`CREATE INDEX "IDX_bb90d1956dafc4068c28aa7560" ON "drive_file" ("folderId") `);
await queryRunner.query(`CREATE TABLE "user" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE, "lastFetchedAt" TIMESTAMP WITH TIME ZONE, "username" character varying(128) NOT NULL, "usernameLower" character varying(128) NOT NULL, "name" character varying(128), "followersCount" integer NOT NULL DEFAULT 0, "followingCount" integer NOT NULL DEFAULT 0, "notesCount" integer NOT NULL DEFAULT 0, "avatarId" character varying(32), "bannerId" character varying(32), "tags" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "avatarUrl" character varying(512), "bannerUrl" character varying(512), "avatarColor" character varying(32), "bannerColor" character varying(32), "isSuspended" boolean NOT NULL DEFAULT false, "isSilenced" boolean NOT NULL DEFAULT false, "isLocked" boolean NOT NULL DEFAULT false, "isBot" boolean NOT NULL DEFAULT false, "isCat" boolean NOT NULL DEFAULT false, "isAdmin" boolean NOT NULL DEFAULT false, "isModerator" boolean NOT NULL DEFAULT false, "isVerified" boolean NOT NULL DEFAULT false, "emojis" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "host" character varying(128), "inbox" character varying(512), "sharedInbox" character varying(512), "featured" character varying(512), "uri" character varying(512), "token" character(16), CONSTRAINT "UQ_a854e557b1b14814750c7c7b0c9" UNIQUE ("token"), CONSTRAINT "REL_58f5c71eaab331645112cf8cfa" UNIQUE ("avatarId"), CONSTRAINT "REL_afc64b53f8db3707ceb34eb28e" UNIQUE ("bannerId"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_e11e649824a45d8ed01d597fd9" ON "user" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_80ca6e6ef65fb9ef34ea8c90f4" ON "user" ("updatedAt") `);
await queryRunner.query(`CREATE INDEX "IDX_a27b942a0d6dcff90e3ee9b5e8" ON "user" ("usernameLower") `);
await queryRunner.query(`CREATE INDEX "IDX_fa99d777623947a5b05f394cae" ON "user" ("tags") `);
await queryRunner.query(`CREATE INDEX "IDX_3252a5df8d5bbd16b281f7799e" ON "user" ("host") `);
await queryRunner.query(`CREATE INDEX "IDX_be623adaa4c566baf5d29ce0c8" ON "user" ("uri") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a854e557b1b14814750c7c7b0c" ON "user" ("token") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5deb01ae162d1d70b80d064c27" ON "user" ("usernameLower", "host") `);
await queryRunner.query(`CREATE TABLE "app" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32), "secret" character varying(64) NOT NULL, "name" character varying(128) NOT NULL, "description" character varying(512) NOT NULL, "permission" character varying(64) array NOT NULL, "callbackUrl" character varying(512), CONSTRAINT "PK_9478629fc093d229df09e560aea" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_048a757923ed8b157e9895da53" ON "app" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_3f5b0899ef90527a3462d7c2cb" ON "app" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_f49922d511d666848f250663c4" ON "app" ("secret") `);
await queryRunner.query(`CREATE TABLE "access_token" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "token" character varying(128) NOT NULL, "hash" character varying(128) NOT NULL, "userId" character varying(32) NOT NULL, "appId" character varying(32) NOT NULL, CONSTRAINT "PK_f20f028607b2603deabd8182d12" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_70ba8f6af34bc924fc9e12adb8" ON "access_token" ("token") `);
await queryRunner.query(`CREATE INDEX "IDX_64c327441248bae40f7d92f34f" ON "access_token" ("hash") `);
await queryRunner.query(`CREATE INDEX "IDX_9949557d0e1b2c19e5344c171e" ON "access_token" ("userId") `);
await queryRunner.query(`CREATE TYPE "note_visibility_enum" AS ENUM('public', 'home', 'followers', 'specified')`);
await queryRunner.query(`CREATE TABLE "note" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "replyId" character varying(32), "renoteId" character varying(32), "text" text, "name" character varying(256), "cw" character varying(512), "appId" character varying(32), "userId" character varying(32) NOT NULL, "viaMobile" boolean NOT NULL DEFAULT false, "localOnly" boolean NOT NULL DEFAULT false, "renoteCount" smallint NOT NULL DEFAULT 0, "repliesCount" smallint NOT NULL DEFAULT 0, "reactions" jsonb NOT NULL DEFAULT '{}', "visibility" "note_visibility_enum" NOT NULL, "uri" character varying(512), "score" integer NOT NULL DEFAULT 0, "fileIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "attachedFileTypes" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "visibleUserIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "mentions" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "mentionedRemoteUsers" text NOT NULL DEFAULT '[]', "emojis" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "tags" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "hasPoll" boolean NOT NULL DEFAULT false, "geo" jsonb DEFAULT null, "userHost" character varying(128), "replyUserId" character varying(32), "replyUserHost" character varying(128), "renoteUserId" character varying(32), "renoteUserHost" character varying(128), CONSTRAINT "PK_96d0c172a4fba276b1bbed43058" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_e7c0567f5261063592f022e9b5" ON "note" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_17cb3553c700a4985dff5a30ff" ON "note" ("replyId") `);
await queryRunner.query(`CREATE INDEX "IDX_52ccc804d7c69037d558bac4c9" ON "note" ("renoteId") `);
await queryRunner.query(`CREATE INDEX "IDX_5b87d9d19127bd5d92026017a7" ON "note" ("userId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_153536c67d05e9adb24e99fc2b" ON "note" ("uri") `);
await queryRunner.query(`CREATE INDEX "IDX_51c063b6a133a9cb87145450f5" ON "note" ("fileIds") `);
await queryRunner.query(`CREATE INDEX "IDX_25dfc71b0369b003a4cd434d0b" ON "note" ("attachedFileTypes") `);
await queryRunner.query(`CREATE INDEX "IDX_796a8c03959361f97dc2be1d5c" ON "note" ("visibleUserIds") `);
await queryRunner.query(`CREATE INDEX "IDX_54ebcb6d27222913b908d56fd8" ON "note" ("mentions") `);
await queryRunner.query(`CREATE INDEX "IDX_88937d94d7443d9a99a76fa5c0" ON "note" ("tags") `);
await queryRunner.query(`CREATE INDEX "IDX_7125a826ab192eb27e11d358a5" ON "note" ("userHost") `);
await queryRunner.query(`CREATE TABLE "poll_vote" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "choice" integer NOT NULL, CONSTRAINT "PK_fd002d371201c472490ba89c6a0" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_0fb627e1c2f753262a74f0562d" ON "poll_vote" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_66d2bd2ee31d14bcc23069a89f" ON "poll_vote" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_aecfbd5ef60374918e63ee95fa" ON "poll_vote" ("noteId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_50bd7164c5b78f1f4a42c4d21f" ON "poll_vote" ("userId", "noteId", "choice") `);
await queryRunner.query(`CREATE TABLE "note_reaction" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "reaction" character varying(128) NOT NULL, CONSTRAINT "PK_767ec729b108799b587a3fcc9cf" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_13761f64257f40c5636d0ff95e" ON "note_reaction" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_45145e4953780f3cd5656f0ea6" ON "note_reaction" ("noteId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ad0c221b25672daf2df320a817" ON "note_reaction" ("userId", "noteId") `);
await queryRunner.query(`CREATE TABLE "note_watching" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "noteUserId" character varying(32) NOT NULL, CONSTRAINT "PK_49286fdb23725945a74aa27d757" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_318cdf42a9cfc11f479bd802bb" ON "note_watching" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_b0134ec406e8d09a540f818288" ON "note_watching" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_03e7028ab8388a3f5e3ce2a861" ON "note_watching" ("noteId") `);
await queryRunner.query(`CREATE INDEX "IDX_44499765eec6b5489d72c4253b" ON "note_watching" ("noteUserId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a42c93c69989ce1d09959df4cf" ON "note_watching" ("userId", "noteId") `);
await queryRunner.query(`CREATE TABLE "note_unread" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "noteUserId" character varying(32) NOT NULL, "isSpecified" boolean NOT NULL, CONSTRAINT "PK_1904eda61a784f57e6e51fa9c1f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_56b0166d34ddae49d8ef7610bb" ON "note_unread" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_e637cba4dc4410218c4251260e" ON "note_unread" ("noteId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d908433a4953cc13216cd9c274" ON "note_unread" ("userId", "noteId") `);
await queryRunner.query(`CREATE TABLE "notification" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "notifieeId" character varying(32) NOT NULL, "notifierId" character varying(32) NOT NULL, "type" character varying(32) NOT NULL, "isRead" boolean NOT NULL DEFAULT false, "noteId" character varying(32), "reaction" character varying(128), "choice" integer, CONSTRAINT "PK_705b6c7cdf9b2c2ff7ac7872cb7" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b11a5e627c41d4dc3170f1d370" ON "notification" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON "notification" ("notifieeId") `);
await queryRunner.query(`CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/assets/ai.png', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT 'https://xn--931a.moe/aiart/yubitun.png', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT true, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "following" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_c76c6e044bdf76ecf8bfb82a645" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_582f8fab771a9040a12961f3e7" ON "following" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_24e0042143a18157b234df186c" ON "following" ("followeeId") `);
await queryRunner.query(`CREATE INDEX "IDX_6516c5a6f3c015b4eed39978be" ON "following" ("followerId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_307be5f1d1252e0388662acb96" ON "following" ("followerId", "followeeId") `);
await queryRunner.query(`CREATE TABLE "instance" ("id" character varying(32) NOT NULL, "caughtAt" TIMESTAMP WITH TIME ZONE NOT NULL, "host" character varying(128) NOT NULL, "system" character varying(64), "usersCount" integer NOT NULL DEFAULT 0, "notesCount" integer NOT NULL DEFAULT 0, "followingCount" integer NOT NULL DEFAULT 0, "followersCount" integer NOT NULL DEFAULT 0, "driveUsage" integer NOT NULL DEFAULT 0, "driveFiles" integer NOT NULL DEFAULT 0, "latestRequestSentAt" TIMESTAMP WITH TIME ZONE, "latestStatus" integer, "latestRequestReceivedAt" TIMESTAMP WITH TIME ZONE, "lastCommunicatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "isNotResponding" boolean NOT NULL DEFAULT false, "isMarkedAsClosed" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_eaf60e4a0c399c9935413e06474" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_2cd3b2a6b4cf0b910b260afe08" ON "instance" ("caughtAt") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_8d5afc98982185799b160e10eb" ON "instance" ("host") `);
await queryRunner.query(`CREATE TABLE "muting" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "muteeId" character varying(32) NOT NULL, "muterId" character varying(32) NOT NULL, CONSTRAINT "PK_2e92d06c8b5c602eeb27ca9ba48" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_f86d57fbca33c7a4e6897490cc" ON "muting" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_ec96b4fed9dae517e0dbbe0675" ON "muting" ("muteeId") `);
await queryRunner.query(`CREATE INDEX "IDX_93060675b4a79a577f31d260c6" ON "muting" ("muterId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1eb9d9824a630321a29fd3b290" ON "muting" ("muterId", "muteeId") `);
await queryRunner.query(`CREATE TABLE "sw_subscription" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "endpoint" character varying(512) NOT NULL, "auth" character varying(256) NOT NULL, "publickey" character varying(128) NOT NULL, CONSTRAINT "PK_e8f763631530051b95eb6279b91" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_97754ca6f2baff9b4abb7f853d" ON "sw_subscription" ("userId") `);
await queryRunner.query(`CREATE TABLE "blocking" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "blockeeId" character varying(32) NOT NULL, "blockerId" character varying(32) NOT NULL, CONSTRAINT "PK_e5d9a541cc1965ee7e048ea09dd" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b9a354f7941c1e779f3b33aea6" ON "blocking" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_2cd4a2743a99671308f5417759" ON "blocking" ("blockeeId") `);
await queryRunner.query(`CREATE INDEX "IDX_0627125f1a8a42c9a1929edb55" ON "blocking" ("blockerId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_98a1bc5cb30dfd159de056549f" ON "blocking" ("blockerId", "blockeeId") `);
await queryRunner.query(`CREATE TABLE "user_list" ("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, CONSTRAINT "PK_87bab75775fd9b1ff822b656402" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b7fcefbdd1c18dce86687531f9" ON "user_list" ("userId") `);
await queryRunner.query(`CREATE TABLE "user_list_joining" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userListId" character varying(32) NOT NULL, CONSTRAINT "PK_11abb3768da1c5f8de101c9df45" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_d844bfc6f3f523a05189076efa" ON "user_list_joining" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_605472305f26818cc93d1baaa7" ON "user_list_joining" ("userListId") `);
await queryRunner.query(`CREATE TABLE "hashtag" ("id" character varying(32) NOT NULL, "name" character varying(128) NOT NULL, "mentionedUserIds" character varying(32) array NOT NULL, "mentionedUsersCount" integer NOT NULL DEFAULT 0, "mentionedLocalUserIds" character varying(32) array NOT NULL, "mentionedLocalUsersCount" integer NOT NULL DEFAULT 0, "mentionedRemoteUserIds" character varying(32) array NOT NULL, "mentionedRemoteUsersCount" integer NOT NULL DEFAULT 0, "attachedUserIds" character varying(32) array NOT NULL, "attachedUsersCount" integer NOT NULL DEFAULT 0, "attachedLocalUserIds" character varying(32) array NOT NULL, "attachedLocalUsersCount" integer NOT NULL DEFAULT 0, "attachedRemoteUserIds" character varying(32) array NOT NULL, "attachedRemoteUsersCount" integer NOT NULL DEFAULT 0, CONSTRAINT "PK_cb36eb8af8412bfa978f1165d78" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_347fec870eafea7b26c8a73bac" ON "hashtag" ("name") `);
await queryRunner.query(`CREATE INDEX "IDX_2710a55f826ee236ea1a62698f" ON "hashtag" ("mentionedUsersCount") `);
await queryRunner.query(`CREATE INDEX "IDX_0e206cec573f1edff4a3062923" ON "hashtag" ("mentionedLocalUsersCount") `);
await queryRunner.query(`CREATE INDEX "IDX_4c02d38a976c3ae132228c6fce" ON "hashtag" ("mentionedRemoteUsersCount") `);
await queryRunner.query(`CREATE INDEX "IDX_d57f9030cd3af7f63ffb1c267c" ON "hashtag" ("attachedUsersCount") `);
await queryRunner.query(`CREATE INDEX "IDX_0c44bf4f680964145f2a68a341" ON "hashtag" ("attachedLocalUsersCount") `);
await queryRunner.query(`CREATE INDEX "IDX_0b03cbcd7e6a7ce068efa8ecc2" ON "hashtag" ("attachedRemoteUsersCount") `);
await queryRunner.query(`CREATE TABLE "note_favorite" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, CONSTRAINT "PK_af0da35a60b9fa4463a62082b36" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_47f4b1892f5d6ba8efb3057d81" ON "note_favorite" ("userId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0f4fb9ad355f3effff221ef245" ON "note_favorite" ("userId", "noteId") `);
await queryRunner.query(`CREATE TABLE "abuse_user_report" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "reporterId" character varying(32) NOT NULL, "comment" character varying(512) NOT NULL, CONSTRAINT "PK_87873f5f5cc5c321a1306b2d18c" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_db2098070b2b5a523c58181f74" ON "abuse_user_report" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_d049123c413e68ca52abe73420" ON "abuse_user_report" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_04cc96756f89d0b7f9473e8cdf" ON "abuse_user_report" ("reporterId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5cd442c3b2e74fdd99dae20243" ON "abuse_user_report" ("userId", "reporterId") `);
await queryRunner.query(`CREATE TABLE "registration_ticket" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "code" character varying(64) NOT NULL, CONSTRAINT "PK_f11696b6fafcf3662d4292734f8" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0ff69e8dfa9fe31bb4a4660f59" ON "registration_ticket" ("code") `);
await queryRunner.query(`CREATE TABLE "messaging_message" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "recipientId" character varying(32) NOT NULL, "text" character varying(4096), "isRead" boolean NOT NULL DEFAULT false, "fileId" character varying(32), CONSTRAINT "PK_db398fd79dc95d0eb8c30456eaa" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_e21cd3646e52ef9c94aaf17c2e" ON "messaging_message" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_5377c307783fce2b6d352e1203" ON "messaging_message" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_cac14a4e3944454a5ce7daa514" ON "messaging_message" ("recipientId") `);
await queryRunner.query(`CREATE TABLE "signin" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "ip" character varying(128) NOT NULL, "headers" jsonb NOT NULL, "success" boolean NOT NULL, CONSTRAINT "PK_9e96ddc025712616fc492b3b588" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_2c308dbdc50d94dc625670055f" ON "signin" ("userId") `);
await queryRunner.query(`CREATE TABLE "auth_session" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "token" character varying(128) NOT NULL, "userId" character varying(32), "appId" character varying(32) NOT NULL, CONSTRAINT "PK_19354ed146424a728c1112a8cbf" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_62cb09e1129f6ec024ef66e183" ON "auth_session" ("token") `);
await queryRunner.query(`CREATE TABLE "follow_request" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "requestId" character varying(128), "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_53a9aa3725f7a3deb150b39dbfc" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_12c01c0d1a79f77d9f6c15fadd" ON "follow_request" ("followeeId") `);
await queryRunner.query(`CREATE INDEX "IDX_a7fd92dd6dc519e6fb435dd108" ON "follow_request" ("followerId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d54a512b822fac7ed52800f6b4" ON "follow_request" ("followerId", "followeeId") `);
await queryRunner.query(`CREATE TABLE "emoji" ("id" character varying(32) NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE, "name" character varying(128) NOT NULL, "host" character varying(128), "url" character varying(512) NOT NULL, "uri" character varying(512), "type" character varying(64), "aliases" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], CONSTRAINT "PK_df74ce05e24999ee01ea0bc50a3" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b37dafc86e9af007e3295c2781" ON "emoji" ("name") `);
await queryRunner.query(`CREATE INDEX "IDX_5900e907bb46516ddf2871327c" ON "emoji" ("host") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_4f4d35e1256c84ae3d1f0eab10" ON "emoji" ("name", "host") `);
await queryRunner.query(`CREATE TABLE "reversi_game" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "startedAt" TIMESTAMP WITH TIME ZONE, "user1Id" character varying(32) NOT NULL, "user2Id" character varying(32) NOT NULL, "user1Accepted" boolean NOT NULL DEFAULT false, "user2Accepted" boolean NOT NULL DEFAULT false, "black" integer, "isStarted" boolean NOT NULL DEFAULT false, "isEnded" boolean NOT NULL DEFAULT false, "winnerId" character varying(32), "surrendered" character varying(32), "logs" jsonb NOT NULL DEFAULT '[]', "map" character varying(64) array NOT NULL, "bw" character varying(32) NOT NULL, "isLlotheo" boolean NOT NULL DEFAULT false, "canPutEverywhere" boolean NOT NULL DEFAULT false, "loopedBoard" boolean NOT NULL DEFAULT false, "form1" jsonb DEFAULT null, "form2" jsonb DEFAULT null, "crc32" character varying(32), CONSTRAINT "PK_76b30eeba71b1193ad7c5311c3f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b46ec40746efceac604142be1c" ON "reversi_game" ("createdAt") `);
await queryRunner.query(`CREATE TABLE "reversi_matching" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "parentId" character varying(32) NOT NULL, "childId" character varying(32) NOT NULL, CONSTRAINT "PK_880bd0afbab232f21c8b9d146cf" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_b604d92d6c7aec38627f6eaf16" ON "reversi_matching" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_3b25402709dd9882048c2bbade" ON "reversi_matching" ("parentId") `);
await queryRunner.query(`CREATE INDEX "IDX_e247b23a3c9b45f89ec1299d06" ON "reversi_matching" ("childId") `);
await queryRunner.query(`CREATE TABLE "user_note_pining" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, CONSTRAINT "PK_a6a2dad4ae000abce2ea9d9b103" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_bfbc6f79ba4007b4ce5097f08d" ON "user_note_pining" ("userId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_410cd649884b501c02d6e72738" ON "user_note_pining" ("userId", "noteId") `);
await queryRunner.query(`CREATE TYPE "poll_notevisibility_enum" AS ENUM('public', 'home', 'followers', 'specified')`);
await queryRunner.query(`CREATE TABLE "poll" ("noteId" character varying(32) NOT NULL, "expiresAt" TIMESTAMP WITH TIME ZONE, "multiple" boolean NOT NULL, "choices" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "votes" integer array NOT NULL, "noteVisibility" "poll_notevisibility_enum" NOT NULL, "userId" character varying(32) NOT NULL, "userHost" character varying(128), CONSTRAINT "REL_da851e06d0dfe2ef397d8b1bf1" UNIQUE ("noteId"), CONSTRAINT "PK_da851e06d0dfe2ef397d8b1bf1b" PRIMARY KEY ("noteId"))`);
await queryRunner.query(`CREATE INDEX "IDX_0610ebcfcfb4a18441a9bcdab2" ON "poll" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_7fa20a12319c7f6dc3aed98c0a" ON "poll" ("userHost") `);
await queryRunner.query(`CREATE TABLE "user_keypair" ("userId" character varying(32) NOT NULL, "publicKey" character varying(4096) NOT NULL, "privateKey" character varying(4096) NOT NULL, CONSTRAINT "REL_f4853eb41ab722fe05f81cedeb" UNIQUE ("userId"), CONSTRAINT "PK_f4853eb41ab722fe05f81cedeb6" PRIMARY KEY ("userId"))`);
await queryRunner.query(`CREATE TABLE "user_publickey" ("userId" character varying(32) NOT NULL, "keyId" character varying(256) NOT NULL, "keyPem" character varying(4096) NOT NULL, CONSTRAINT "REL_10c146e4b39b443ede016f6736" UNIQUE ("userId"), CONSTRAINT "PK_10c146e4b39b443ede016f6736d" PRIMARY KEY ("userId"))`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_171e64971c780ebd23fae140bb" ON "user_publickey" ("keyId") `);
await queryRunner.query(`CREATE TABLE "user_profile" ("userId" character varying(32) NOT NULL, "location" character varying(128), "birthday" character(10), "description" character varying(1024), "fields" jsonb NOT NULL DEFAULT '[]', "url" character varying(512), "email" character varying(128), "emailVerifyCode" character varying(128), "emailVerified" boolean NOT NULL DEFAULT false, "twoFactorTempSecret" character varying(128), "twoFactorSecret" character varying(128), "twoFactorEnabled" boolean NOT NULL DEFAULT false, "password" character varying(128), "clientData" jsonb NOT NULL DEFAULT '{}', "autoWatch" boolean NOT NULL DEFAULT false, "autoAcceptFollowed" boolean NOT NULL DEFAULT false, "alwaysMarkNsfw" boolean NOT NULL DEFAULT false, "carefulBot" boolean NOT NULL DEFAULT false, "twitter" boolean NOT NULL DEFAULT false, "twitterAccessToken" character varying(64) DEFAULT null, "twitterAccessTokenSecret" character varying(64) DEFAULT null, "twitterUserId" character varying(64) DEFAULT null, "twitterScreenName" character varying(64) DEFAULT null, "github" boolean NOT NULL DEFAULT false, "githubAccessToken" character varying(64) DEFAULT null, "githubId" integer DEFAULT null, "githubLogin" character varying(64) DEFAULT null, "discord" boolean NOT NULL DEFAULT false, "discordAccessToken" character varying(64) DEFAULT null, "discordRefreshToken" character varying(64) DEFAULT null, "discordExpiresDate" integer DEFAULT null, "discordId" character varying(64) DEFAULT null, "discordUsername" character varying(64) DEFAULT null, "discordDiscriminator" character varying(64) DEFAULT null, "userHost" character varying(128), CONSTRAINT "REL_51cb79b5555effaf7d69ba1cff" UNIQUE ("userId"), CONSTRAINT "PK_51cb79b5555effaf7d69ba1cff9" PRIMARY KEY ("userId"))`);
await queryRunner.query(`CREATE INDEX "IDX_dce530b98e454793dac5ec2f5a" ON "user_profile" ("userHost") `);
await queryRunner.query(`CREATE TYPE "__chart__active_users_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__active_users" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__active_users_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_count" bigint NOT NULL, "___remote_count" bigint NOT NULL, CONSTRAINT "PK_317237a9f733b970604a11e314f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__drive_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__drive" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__drive_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_totalCount" bigint NOT NULL, "___local_totalSize" bigint NOT NULL, "___local_incCount" bigint NOT NULL, "___local_incSize" bigint NOT NULL, "___local_decCount" bigint NOT NULL, "___local_decSize" bigint NOT NULL, "___remote_totalCount" bigint NOT NULL, "___remote_totalSize" bigint NOT NULL, "___remote_incCount" bigint NOT NULL, "___remote_incSize" bigint NOT NULL, "___remote_decCount" bigint NOT NULL, "___remote_decSize" bigint NOT NULL, CONSTRAINT "PK_f96bc548a765cd4b3b354221ce7" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__federation_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__federation" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__federation_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___instance_total" bigint NOT NULL, "___instance_inc" bigint NOT NULL, "___instance_dec" bigint NOT NULL, CONSTRAINT "PK_b39dcd31a0fe1a7757e348e85fd" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__hashtag_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__hashtag" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__hashtag_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_count" bigint NOT NULL, "___remote_count" bigint NOT NULL, CONSTRAINT "PK_c32f1ea2b44a5d2f7881e37f8f9" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__instance_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__instance" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__instance_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___requests_failed" bigint NOT NULL, "___requests_succeeded" bigint NOT NULL, "___requests_received" bigint NOT NULL, "___notes_total" bigint NOT NULL, "___notes_inc" bigint NOT NULL, "___notes_dec" bigint NOT NULL, "___notes_diffs_normal" bigint NOT NULL, "___notes_diffs_reply" bigint NOT NULL, "___notes_diffs_renote" bigint NOT NULL, "___users_total" bigint NOT NULL, "___users_inc" bigint NOT NULL, "___users_dec" bigint NOT NULL, "___following_total" bigint NOT NULL, "___following_inc" bigint NOT NULL, "___following_dec" bigint NOT NULL, "___followers_total" bigint NOT NULL, "___followers_inc" bigint NOT NULL, "___followers_dec" bigint NOT NULL, "___drive_totalFiles" bigint NOT NULL, "___drive_totalUsage" bigint NOT NULL, "___drive_incFiles" bigint NOT NULL, "___drive_incUsage" bigint NOT NULL, "___drive_decFiles" bigint NOT NULL, "___drive_decUsage" bigint NOT NULL, CONSTRAINT "PK_1267c67c7c2d47b4903975f2c00" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__network_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__network" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__network_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___incomingRequests" bigint NOT NULL, "___outgoingRequests" bigint NOT NULL, "___totalTime" bigint NOT NULL, "___incomingBytes" bigint NOT NULL, "___outgoingBytes" bigint NOT NULL, CONSTRAINT "PK_bc4290c2e27fad14ef0c1ca93f3" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__notes_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__notes" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__notes_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_total" bigint NOT NULL, "___local_inc" bigint NOT NULL, "___local_dec" bigint NOT NULL, "___local_diffs_normal" bigint NOT NULL, "___local_diffs_reply" bigint NOT NULL, "___local_diffs_renote" bigint NOT NULL, "___remote_total" bigint NOT NULL, "___remote_inc" bigint NOT NULL, "___remote_dec" bigint NOT NULL, "___remote_diffs_normal" bigint NOT NULL, "___remote_diffs_reply" bigint NOT NULL, "___remote_diffs_renote" bigint NOT NULL, CONSTRAINT "PK_0aec823fa85c7f901bdb3863b14" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__per_user_drive_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__per_user_drive" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_drive_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___totalCount" bigint NOT NULL, "___totalSize" bigint NOT NULL, "___incCount" bigint NOT NULL, "___incSize" bigint NOT NULL, "___decCount" bigint NOT NULL, "___decSize" bigint NOT NULL, CONSTRAINT "PK_d0ef23d24d666e1a44a0cd3d208" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__per_user_following_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__per_user_following" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_following_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_followings_total" bigint NOT NULL, "___local_followings_inc" bigint NOT NULL, "___local_followings_dec" bigint NOT NULL, "___local_followers_total" bigint NOT NULL, "___local_followers_inc" bigint NOT NULL, "___local_followers_dec" bigint NOT NULL, "___remote_followings_total" bigint NOT NULL, "___remote_followings_inc" bigint NOT NULL, "___remote_followings_dec" bigint NOT NULL, "___remote_followers_total" bigint NOT NULL, "___remote_followers_inc" bigint NOT NULL, "___remote_followers_dec" bigint NOT NULL, CONSTRAINT "PK_85bb1b540363a29c2fec83bd907" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__per_user_notes_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__per_user_notes" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_notes_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___total" bigint NOT NULL, "___inc" bigint NOT NULL, "___dec" bigint NOT NULL, "___diffs_normal" bigint NOT NULL, "___diffs_reply" bigint NOT NULL, "___diffs_renote" bigint NOT NULL, CONSTRAINT "PK_334acf6e915af2f29edc11b8e50" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__per_user_reaction_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__per_user_reaction" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_reaction_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_count" bigint NOT NULL, "___remote_count" bigint NOT NULL, CONSTRAINT "PK_984f54dae441e65b633e8d27a7f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__test_grouped_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__test_grouped" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__test_grouped_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___foo_total" bigint NOT NULL, "___foo_inc" bigint NOT NULL, "___foo_dec" bigint NOT NULL, CONSTRAINT "PK_f4a2b175d308695af30d4293272" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__test_unique_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__test_unique" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__test_unique_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___foo" bigint NOT NULL, CONSTRAINT "PK_409bac9c97cc612d8500012319d" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__test_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__test" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__test_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___foo_total" bigint NOT NULL, "___foo_inc" bigint NOT NULL, "___foo_dec" bigint NOT NULL, CONSTRAINT "PK_b4bc31dffbd1b785276a3ecfc1e" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TYPE "__chart__users_span_enum" AS ENUM('hour', 'day')`);
await queryRunner.query(`CREATE TABLE "__chart__users" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__users_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_total" bigint NOT NULL, "___local_inc" bigint NOT NULL, "___local_dec" bigint NOT NULL, "___remote_total" bigint NOT NULL, "___remote_inc" bigint NOT NULL, "___remote_dec" bigint NOT NULL, CONSTRAINT "PK_4dfcf2c78d03524b9eb2c99d328" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "drive_folder" ADD CONSTRAINT "FK_f4fc06e49c0171c85f1c48060d2" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "drive_folder" ADD CONSTRAINT "FK_00ceffb0cdc238b3233294f08f2" FOREIGN KEY ("parentId") REFERENCES "drive_folder"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD CONSTRAINT "FK_860fa6f6c7df5bb887249fba22e" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "drive_file" ADD CONSTRAINT "FK_bb90d1956dafc4068c28aa7560a" FOREIGN KEY ("folderId") REFERENCES "drive_folder"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_58f5c71eaab331645112cf8cfa5" FOREIGN KEY ("avatarId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_afc64b53f8db3707ceb34eb28e2" FOREIGN KEY ("bannerId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "app" ADD CONSTRAINT "FK_3f5b0899ef90527a3462d7c2cb3" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "access_token" ADD CONSTRAINT "FK_9949557d0e1b2c19e5344c171e9" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "access_token" ADD CONSTRAINT "FK_a3ff16c90cc87a82a0b5959e560" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_17cb3553c700a4985dff5a30ff5" FOREIGN KEY ("replyId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_52ccc804d7c69037d558bac4c96" FOREIGN KEY ("renoteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_ec5c201576192ba8904c345c5cc" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_5b87d9d19127bd5d92026017a7b" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "poll_vote" ADD CONSTRAINT "FK_66d2bd2ee31d14bcc23069a89f8" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "poll_vote" ADD CONSTRAINT "FK_aecfbd5ef60374918e63ee95fa7" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_reaction" ADD CONSTRAINT "FK_13761f64257f40c5636d0ff95ee" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_reaction" ADD CONSTRAINT "FK_45145e4953780f3cd5656f0ea6a" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_watching" ADD CONSTRAINT "FK_b0134ec406e8d09a540f8182888" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_watching" ADD CONSTRAINT "FK_03e7028ab8388a3f5e3ce2a8619" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_unread" ADD CONSTRAINT "FK_56b0166d34ddae49d8ef7610bb9" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_unread" ADD CONSTRAINT "FK_e637cba4dc4410218c4251260e4" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_3c601b70a1066d2c8b517094cb9" FOREIGN KEY ("notifieeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_3b4e96eec8d36a8bbb9d02aa710" FOREIGN KEY ("notifierId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_769cb6b73a1efe22ddf733ac453" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "following" ADD CONSTRAINT "FK_24e0042143a18157b234df186c3" FOREIGN KEY ("followeeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "following" ADD CONSTRAINT "FK_6516c5a6f3c015b4eed39978be5" FOREIGN KEY ("followerId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "muting" ADD CONSTRAINT "FK_ec96b4fed9dae517e0dbbe0675c" FOREIGN KEY ("muteeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "muting" ADD CONSTRAINT "FK_93060675b4a79a577f31d260c67" FOREIGN KEY ("muterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "sw_subscription" ADD CONSTRAINT "FK_97754ca6f2baff9b4abb7f853dd" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "blocking" ADD CONSTRAINT "FK_2cd4a2743a99671308f5417759e" FOREIGN KEY ("blockeeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "blocking" ADD CONSTRAINT "FK_0627125f1a8a42c9a1929edb552" FOREIGN KEY ("blockerId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_list" ADD CONSTRAINT "FK_b7fcefbdd1c18dce86687531f99" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_list_joining" ADD CONSTRAINT "FK_d844bfc6f3f523a05189076efaa" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_list_joining" ADD CONSTRAINT "FK_605472305f26818cc93d1baaa74" FOREIGN KEY ("userListId") REFERENCES "user_list"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_favorite" ADD CONSTRAINT "FK_47f4b1892f5d6ba8efb3057d81a" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "note_favorite" ADD CONSTRAINT "FK_0e00498f180193423c992bc4370" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_d049123c413e68ca52abe734203" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_04cc96756f89d0b7f9473e8cdf3" FOREIGN KEY ("reporterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_5377c307783fce2b6d352e1203b" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_cac14a4e3944454a5ce7daa5142" FOREIGN KEY ("recipientId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "signin" ADD CONSTRAINT "FK_2c308dbdc50d94dc625670055f7" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "FK_c072b729d71697f959bde66ade0" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "FK_dbe037d4bddd17b03a1dc778dee" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "follow_request" ADD CONSTRAINT "FK_12c01c0d1a79f77d9f6c15fadd2" FOREIGN KEY ("followeeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "follow_request" ADD CONSTRAINT "FK_a7fd92dd6dc519e6fb435dd108f" FOREIGN KEY ("followerId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "reversi_game" ADD CONSTRAINT "FK_f7467510c60a45ce5aca6292743" FOREIGN KEY ("user1Id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "reversi_game" ADD CONSTRAINT "FK_6649a4e8c5d5cf32fb03b5da9f6" FOREIGN KEY ("user2Id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "reversi_matching" ADD CONSTRAINT "FK_3b25402709dd9882048c2bbade0" FOREIGN KEY ("parentId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "reversi_matching" ADD CONSTRAINT "FK_e247b23a3c9b45f89ec1299d066" FOREIGN KEY ("childId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_note_pining" ADD CONSTRAINT "FK_bfbc6f79ba4007b4ce5097f08d6" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_note_pining" ADD CONSTRAINT "FK_68881008f7c3588ad7ecae471cf" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "poll" ADD CONSTRAINT "FK_da851e06d0dfe2ef397d8b1bf1b" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_keypair" ADD CONSTRAINT "FK_f4853eb41ab722fe05f81cedeb6" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "FK_10c146e4b39b443ede016f6736d" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "FK_51cb79b5555effaf7d69ba1cff9" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "FK_51cb79b5555effaf7d69ba1cff9"`);
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "FK_10c146e4b39b443ede016f6736d"`);
await queryRunner.query(`ALTER TABLE "user_keypair" DROP CONSTRAINT "FK_f4853eb41ab722fe05f81cedeb6"`);
await queryRunner.query(`ALTER TABLE "poll" DROP CONSTRAINT "FK_da851e06d0dfe2ef397d8b1bf1b"`);
await queryRunner.query(`ALTER TABLE "user_note_pining" DROP CONSTRAINT "FK_68881008f7c3588ad7ecae471cf"`);
await queryRunner.query(`ALTER TABLE "user_note_pining" DROP CONSTRAINT "FK_bfbc6f79ba4007b4ce5097f08d6"`);
await queryRunner.query(`ALTER TABLE "reversi_matching" DROP CONSTRAINT "FK_e247b23a3c9b45f89ec1299d066"`);
await queryRunner.query(`ALTER TABLE "reversi_matching" DROP CONSTRAINT "FK_3b25402709dd9882048c2bbade0"`);
await queryRunner.query(`ALTER TABLE "reversi_game" DROP CONSTRAINT "FK_6649a4e8c5d5cf32fb03b5da9f6"`);
await queryRunner.query(`ALTER TABLE "reversi_game" DROP CONSTRAINT "FK_f7467510c60a45ce5aca6292743"`);
await queryRunner.query(`ALTER TABLE "follow_request" DROP CONSTRAINT "FK_a7fd92dd6dc519e6fb435dd108f"`);
await queryRunner.query(`ALTER TABLE "follow_request" DROP CONSTRAINT "FK_12c01c0d1a79f77d9f6c15fadd2"`);
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "FK_dbe037d4bddd17b03a1dc778dee"`);
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "FK_c072b729d71697f959bde66ade0"`);
await queryRunner.query(`ALTER TABLE "signin" DROP CONSTRAINT "FK_2c308dbdc50d94dc625670055f7"`);
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b"`);
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_cac14a4e3944454a5ce7daa5142"`);
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_5377c307783fce2b6d352e1203b"`);
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_04cc96756f89d0b7f9473e8cdf3"`);
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_d049123c413e68ca52abe734203"`);
await queryRunner.query(`ALTER TABLE "note_favorite" DROP CONSTRAINT "FK_0e00498f180193423c992bc4370"`);
await queryRunner.query(`ALTER TABLE "note_favorite" DROP CONSTRAINT "FK_47f4b1892f5d6ba8efb3057d81a"`);
await queryRunner.query(`ALTER TABLE "user_list_joining" DROP CONSTRAINT "FK_605472305f26818cc93d1baaa74"`);
await queryRunner.query(`ALTER TABLE "user_list_joining" DROP CONSTRAINT "FK_d844bfc6f3f523a05189076efaa"`);
await queryRunner.query(`ALTER TABLE "user_list" DROP CONSTRAINT "FK_b7fcefbdd1c18dce86687531f99"`);
await queryRunner.query(`ALTER TABLE "blocking" DROP CONSTRAINT "FK_0627125f1a8a42c9a1929edb552"`);
await queryRunner.query(`ALTER TABLE "blocking" DROP CONSTRAINT "FK_2cd4a2743a99671308f5417759e"`);
await queryRunner.query(`ALTER TABLE "sw_subscription" DROP CONSTRAINT "FK_97754ca6f2baff9b4abb7f853dd"`);
await queryRunner.query(`ALTER TABLE "muting" DROP CONSTRAINT "FK_93060675b4a79a577f31d260c67"`);
await queryRunner.query(`ALTER TABLE "muting" DROP CONSTRAINT "FK_ec96b4fed9dae517e0dbbe0675c"`);
await queryRunner.query(`ALTER TABLE "following" DROP CONSTRAINT "FK_6516c5a6f3c015b4eed39978be5"`);
await queryRunner.query(`ALTER TABLE "following" DROP CONSTRAINT "FK_24e0042143a18157b234df186c3"`);
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_769cb6b73a1efe22ddf733ac453"`);
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_3b4e96eec8d36a8bbb9d02aa710"`);
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_3c601b70a1066d2c8b517094cb9"`);
await queryRunner.query(`ALTER TABLE "note_unread" DROP CONSTRAINT "FK_e637cba4dc4410218c4251260e4"`);
await queryRunner.query(`ALTER TABLE "note_unread" DROP CONSTRAINT "FK_56b0166d34ddae49d8ef7610bb9"`);
await queryRunner.query(`ALTER TABLE "note_watching" DROP CONSTRAINT "FK_03e7028ab8388a3f5e3ce2a8619"`);
await queryRunner.query(`ALTER TABLE "note_watching" DROP CONSTRAINT "FK_b0134ec406e8d09a540f8182888"`);
await queryRunner.query(`ALTER TABLE "note_reaction" DROP CONSTRAINT "FK_45145e4953780f3cd5656f0ea6a"`);
await queryRunner.query(`ALTER TABLE "note_reaction" DROP CONSTRAINT "FK_13761f64257f40c5636d0ff95ee"`);
await queryRunner.query(`ALTER TABLE "poll_vote" DROP CONSTRAINT "FK_aecfbd5ef60374918e63ee95fa7"`);
await queryRunner.query(`ALTER TABLE "poll_vote" DROP CONSTRAINT "FK_66d2bd2ee31d14bcc23069a89f8"`);
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_5b87d9d19127bd5d92026017a7b"`);
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_ec5c201576192ba8904c345c5cc"`);
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_52ccc804d7c69037d558bac4c96"`);
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_17cb3553c700a4985dff5a30ff5"`);
await queryRunner.query(`ALTER TABLE "access_token" DROP CONSTRAINT "FK_a3ff16c90cc87a82a0b5959e560"`);
await queryRunner.query(`ALTER TABLE "access_token" DROP CONSTRAINT "FK_9949557d0e1b2c19e5344c171e9"`);
await queryRunner.query(`ALTER TABLE "app" DROP CONSTRAINT "FK_3f5b0899ef90527a3462d7c2cb3"`);
await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_afc64b53f8db3707ceb34eb28e2"`);
await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_58f5c71eaab331645112cf8cfa5"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP CONSTRAINT "FK_bb90d1956dafc4068c28aa7560a"`);
await queryRunner.query(`ALTER TABLE "drive_file" DROP CONSTRAINT "FK_860fa6f6c7df5bb887249fba22e"`);
await queryRunner.query(`ALTER TABLE "drive_folder" DROP CONSTRAINT "FK_00ceffb0cdc238b3233294f08f2"`);
await queryRunner.query(`ALTER TABLE "drive_folder" DROP CONSTRAINT "FK_f4fc06e49c0171c85f1c48060d2"`);
await queryRunner.query(`DROP TABLE "__chart__users"`);
await queryRunner.query(`DROP TYPE "__chart__users_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__test"`);
await queryRunner.query(`DROP TYPE "__chart__test_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__test_unique"`);
await queryRunner.query(`DROP TYPE "__chart__test_unique_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__test_grouped"`);
await queryRunner.query(`DROP TYPE "__chart__test_grouped_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__per_user_reaction"`);
await queryRunner.query(`DROP TYPE "__chart__per_user_reaction_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__per_user_notes"`);
await queryRunner.query(`DROP TYPE "__chart__per_user_notes_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__per_user_following"`);
await queryRunner.query(`DROP TYPE "__chart__per_user_following_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__per_user_drive"`);
await queryRunner.query(`DROP TYPE "__chart__per_user_drive_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__notes"`);
await queryRunner.query(`DROP TYPE "__chart__notes_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__network"`);
await queryRunner.query(`DROP TYPE "__chart__network_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__instance"`);
await queryRunner.query(`DROP TYPE "__chart__instance_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__hashtag"`);
await queryRunner.query(`DROP TYPE "__chart__hashtag_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__federation"`);
await queryRunner.query(`DROP TYPE "__chart__federation_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__drive"`);
await queryRunner.query(`DROP TYPE "__chart__drive_span_enum"`);
await queryRunner.query(`DROP TABLE "__chart__active_users"`);
await queryRunner.query(`DROP TYPE "__chart__active_users_span_enum"`);
await queryRunner.query(`DROP INDEX "IDX_dce530b98e454793dac5ec2f5a"`);
await queryRunner.query(`DROP TABLE "user_profile"`);
await queryRunner.query(`DROP INDEX "IDX_171e64971c780ebd23fae140bb"`);
await queryRunner.query(`DROP TABLE "user_publickey"`);
await queryRunner.query(`DROP TABLE "user_keypair"`);
await queryRunner.query(`DROP INDEX "IDX_7fa20a12319c7f6dc3aed98c0a"`);
await queryRunner.query(`DROP INDEX "IDX_0610ebcfcfb4a18441a9bcdab2"`);
await queryRunner.query(`DROP TABLE "poll"`);
await queryRunner.query(`DROP TYPE "poll_notevisibility_enum"`);
await queryRunner.query(`DROP INDEX "IDX_410cd649884b501c02d6e72738"`);
await queryRunner.query(`DROP INDEX "IDX_bfbc6f79ba4007b4ce5097f08d"`);
await queryRunner.query(`DROP TABLE "user_note_pining"`);
await queryRunner.query(`DROP INDEX "IDX_e247b23a3c9b45f89ec1299d06"`);
await queryRunner.query(`DROP INDEX "IDX_3b25402709dd9882048c2bbade"`);
await queryRunner.query(`DROP INDEX "IDX_b604d92d6c7aec38627f6eaf16"`);
await queryRunner.query(`DROP TABLE "reversi_matching"`);
await queryRunner.query(`DROP INDEX "IDX_b46ec40746efceac604142be1c"`);
await queryRunner.query(`DROP TABLE "reversi_game"`);
await queryRunner.query(`DROP INDEX "IDX_4f4d35e1256c84ae3d1f0eab10"`);
await queryRunner.query(`DROP INDEX "IDX_5900e907bb46516ddf2871327c"`);
await queryRunner.query(`DROP INDEX "IDX_b37dafc86e9af007e3295c2781"`);
await queryRunner.query(`DROP TABLE "emoji"`);
await queryRunner.query(`DROP INDEX "IDX_d54a512b822fac7ed52800f6b4"`);
await queryRunner.query(`DROP INDEX "IDX_a7fd92dd6dc519e6fb435dd108"`);
await queryRunner.query(`DROP INDEX "IDX_12c01c0d1a79f77d9f6c15fadd"`);
await queryRunner.query(`DROP TABLE "follow_request"`);
await queryRunner.query(`DROP INDEX "IDX_62cb09e1129f6ec024ef66e183"`);
await queryRunner.query(`DROP TABLE "auth_session"`);
await queryRunner.query(`DROP INDEX "IDX_2c308dbdc50d94dc625670055f"`);
await queryRunner.query(`DROP TABLE "signin"`);
await queryRunner.query(`DROP INDEX "IDX_cac14a4e3944454a5ce7daa514"`);
await queryRunner.query(`DROP INDEX "IDX_5377c307783fce2b6d352e1203"`);
await queryRunner.query(`DROP INDEX "IDX_e21cd3646e52ef9c94aaf17c2e"`);
await queryRunner.query(`DROP TABLE "messaging_message"`);
await queryRunner.query(`DROP INDEX "IDX_0ff69e8dfa9fe31bb4a4660f59"`);
await queryRunner.query(`DROP TABLE "registration_ticket"`);
await queryRunner.query(`DROP INDEX "IDX_5cd442c3b2e74fdd99dae20243"`);
await queryRunner.query(`DROP INDEX "IDX_04cc96756f89d0b7f9473e8cdf"`);
await queryRunner.query(`DROP INDEX "IDX_d049123c413e68ca52abe73420"`);
await queryRunner.query(`DROP INDEX "IDX_db2098070b2b5a523c58181f74"`);
await queryRunner.query(`DROP TABLE "abuse_user_report"`);
await queryRunner.query(`DROP INDEX "IDX_0f4fb9ad355f3effff221ef245"`);
await queryRunner.query(`DROP INDEX "IDX_47f4b1892f5d6ba8efb3057d81"`);
await queryRunner.query(`DROP TABLE "note_favorite"`);
await queryRunner.query(`DROP INDEX "IDX_0b03cbcd7e6a7ce068efa8ecc2"`);
await queryRunner.query(`DROP INDEX "IDX_0c44bf4f680964145f2a68a341"`);
await queryRunner.query(`DROP INDEX "IDX_d57f9030cd3af7f63ffb1c267c"`);
await queryRunner.query(`DROP INDEX "IDX_4c02d38a976c3ae132228c6fce"`);
await queryRunner.query(`DROP INDEX "IDX_0e206cec573f1edff4a3062923"`);
await queryRunner.query(`DROP INDEX "IDX_2710a55f826ee236ea1a62698f"`);
await queryRunner.query(`DROP INDEX "IDX_347fec870eafea7b26c8a73bac"`);
await queryRunner.query(`DROP TABLE "hashtag"`);
await queryRunner.query(`DROP INDEX "IDX_605472305f26818cc93d1baaa7"`);
await queryRunner.query(`DROP INDEX "IDX_d844bfc6f3f523a05189076efa"`);
await queryRunner.query(`DROP TABLE "user_list_joining"`);
await queryRunner.query(`DROP INDEX "IDX_b7fcefbdd1c18dce86687531f9"`);
await queryRunner.query(`DROP TABLE "user_list"`);
await queryRunner.query(`DROP INDEX "IDX_98a1bc5cb30dfd159de056549f"`);
await queryRunner.query(`DROP INDEX "IDX_0627125f1a8a42c9a1929edb55"`);
await queryRunner.query(`DROP INDEX "IDX_2cd4a2743a99671308f5417759"`);
await queryRunner.query(`DROP INDEX "IDX_b9a354f7941c1e779f3b33aea6"`);
await queryRunner.query(`DROP TABLE "blocking"`);
await queryRunner.query(`DROP INDEX "IDX_97754ca6f2baff9b4abb7f853d"`);
await queryRunner.query(`DROP TABLE "sw_subscription"`);
await queryRunner.query(`DROP INDEX "IDX_1eb9d9824a630321a29fd3b290"`);
await queryRunner.query(`DROP INDEX "IDX_93060675b4a79a577f31d260c6"`);
await queryRunner.query(`DROP INDEX "IDX_ec96b4fed9dae517e0dbbe0675"`);
await queryRunner.query(`DROP INDEX "IDX_f86d57fbca33c7a4e6897490cc"`);
await queryRunner.query(`DROP TABLE "muting"`);
await queryRunner.query(`DROP INDEX "IDX_8d5afc98982185799b160e10eb"`);
await queryRunner.query(`DROP INDEX "IDX_2cd3b2a6b4cf0b910b260afe08"`);
await queryRunner.query(`DROP TABLE "instance"`);
await queryRunner.query(`DROP INDEX "IDX_307be5f1d1252e0388662acb96"`);
await queryRunner.query(`DROP INDEX "IDX_6516c5a6f3c015b4eed39978be"`);
await queryRunner.query(`DROP INDEX "IDX_24e0042143a18157b234df186c"`);
await queryRunner.query(`DROP INDEX "IDX_582f8fab771a9040a12961f3e7"`);
await queryRunner.query(`DROP TABLE "following"`);
await queryRunner.query(`DROP TABLE "meta"`);
await queryRunner.query(`DROP INDEX "IDX_3c601b70a1066d2c8b517094cb"`);
await queryRunner.query(`DROP INDEX "IDX_b11a5e627c41d4dc3170f1d370"`);
await queryRunner.query(`DROP TABLE "notification"`);
await queryRunner.query(`DROP INDEX "IDX_d908433a4953cc13216cd9c274"`);
await queryRunner.query(`DROP INDEX "IDX_e637cba4dc4410218c4251260e"`);
await queryRunner.query(`DROP INDEX "IDX_56b0166d34ddae49d8ef7610bb"`);
await queryRunner.query(`DROP TABLE "note_unread"`);
await queryRunner.query(`DROP INDEX "IDX_a42c93c69989ce1d09959df4cf"`);
await queryRunner.query(`DROP INDEX "IDX_44499765eec6b5489d72c4253b"`);
await queryRunner.query(`DROP INDEX "IDX_03e7028ab8388a3f5e3ce2a861"`);
await queryRunner.query(`DROP INDEX "IDX_b0134ec406e8d09a540f818288"`);
await queryRunner.query(`DROP INDEX "IDX_318cdf42a9cfc11f479bd802bb"`);
await queryRunner.query(`DROP TABLE "note_watching"`);
await queryRunner.query(`DROP INDEX "IDX_ad0c221b25672daf2df320a817"`);
await queryRunner.query(`DROP INDEX "IDX_45145e4953780f3cd5656f0ea6"`);
await queryRunner.query(`DROP INDEX "IDX_13761f64257f40c5636d0ff95e"`);
await queryRunner.query(`DROP INDEX "IDX_01f4581f114e0ebd2bbb876f0b"`);
await queryRunner.query(`DROP TABLE "note_reaction"`);
await queryRunner.query(`DROP INDEX "IDX_50bd7164c5b78f1f4a42c4d21f"`);
await queryRunner.query(`DROP INDEX "IDX_aecfbd5ef60374918e63ee95fa"`);
await queryRunner.query(`DROP INDEX "IDX_66d2bd2ee31d14bcc23069a89f"`);
await queryRunner.query(`DROP INDEX "IDX_0fb627e1c2f753262a74f0562d"`);
await queryRunner.query(`DROP TABLE "poll_vote"`);
await queryRunner.query(`DROP INDEX "IDX_7125a826ab192eb27e11d358a5"`);
await queryRunner.query(`DROP INDEX "IDX_88937d94d7443d9a99a76fa5c0"`);
await queryRunner.query(`DROP INDEX "IDX_54ebcb6d27222913b908d56fd8"`);
await queryRunner.query(`DROP INDEX "IDX_796a8c03959361f97dc2be1d5c"`);
await queryRunner.query(`DROP INDEX "IDX_25dfc71b0369b003a4cd434d0b"`);
await queryRunner.query(`DROP INDEX "IDX_51c063b6a133a9cb87145450f5"`);
await queryRunner.query(`DROP INDEX "IDX_153536c67d05e9adb24e99fc2b"`);
await queryRunner.query(`DROP INDEX "IDX_5b87d9d19127bd5d92026017a7"`);
await queryRunner.query(`DROP INDEX "IDX_52ccc804d7c69037d558bac4c9"`);
await queryRunner.query(`DROP INDEX "IDX_17cb3553c700a4985dff5a30ff"`);
await queryRunner.query(`DROP INDEX "IDX_e7c0567f5261063592f022e9b5"`);
await queryRunner.query(`DROP TABLE "note"`);
await queryRunner.query(`DROP TYPE "note_visibility_enum"`);
await queryRunner.query(`DROP INDEX "IDX_9949557d0e1b2c19e5344c171e"`);
await queryRunner.query(`DROP INDEX "IDX_64c327441248bae40f7d92f34f"`);
await queryRunner.query(`DROP INDEX "IDX_70ba8f6af34bc924fc9e12adb8"`);
await queryRunner.query(`DROP TABLE "access_token"`);
await queryRunner.query(`DROP INDEX "IDX_f49922d511d666848f250663c4"`);
await queryRunner.query(`DROP INDEX "IDX_3f5b0899ef90527a3462d7c2cb"`);
await queryRunner.query(`DROP INDEX "IDX_048a757923ed8b157e9895da53"`);
await queryRunner.query(`DROP TABLE "app"`);
await queryRunner.query(`DROP INDEX "IDX_5deb01ae162d1d70b80d064c27"`);
await queryRunner.query(`DROP INDEX "IDX_a854e557b1b14814750c7c7b0c"`);
await queryRunner.query(`DROP INDEX "IDX_be623adaa4c566baf5d29ce0c8"`);
await queryRunner.query(`DROP INDEX "IDX_3252a5df8d5bbd16b281f7799e"`);
await queryRunner.query(`DROP INDEX "IDX_fa99d777623947a5b05f394cae"`);
await queryRunner.query(`DROP INDEX "IDX_a27b942a0d6dcff90e3ee9b5e8"`);
await queryRunner.query(`DROP INDEX "IDX_80ca6e6ef65fb9ef34ea8c90f4"`);
await queryRunner.query(`DROP INDEX "IDX_e11e649824a45d8ed01d597fd9"`);
await queryRunner.query(`DROP TABLE "user"`);
await queryRunner.query(`DROP INDEX "IDX_bb90d1956dafc4068c28aa7560"`);
await queryRunner.query(`DROP INDEX "IDX_e5848eac4940934e23dbc17581"`);
await queryRunner.query(`DROP INDEX "IDX_c55b2b7c284d9fef98026fc88e"`);
await queryRunner.query(`DROP INDEX "IDX_e74022ce9a074b3866f70e0d27"`);
await queryRunner.query(`DROP INDEX "IDX_d85a184c2540d2deba33daf642"`);
await queryRunner.query(`DROP INDEX "IDX_a40b8df8c989d7db937ea27cf6"`);
await queryRunner.query(`DROP INDEX "IDX_37bb9a1b4585f8a3beb24c62d6"`);
await queryRunner.query(`DROP INDEX "IDX_92779627994ac79277f070c91e"`);
await queryRunner.query(`DROP INDEX "IDX_860fa6f6c7df5bb887249fba22"`);
await queryRunner.query(`DROP INDEX "IDX_c8dfad3b72196dd1d6b5db168a"`);
await queryRunner.query(`DROP TABLE "drive_file"`);
await queryRunner.query(`DROP INDEX "IDX_00ceffb0cdc238b3233294f08f"`);
await queryRunner.query(`DROP INDEX "IDX_f4fc06e49c0171c85f1c48060d"`);
await queryRunner.query(`DROP INDEX "IDX_02878d441ceae15ce060b73daf"`);
await queryRunner.query(`DROP TABLE "drive_folder"`);
await queryRunner.query(`DROP INDEX "IDX_584b536b49e53ac81beb39a177"`);
await queryRunner.query(`DROP INDEX "IDX_8cb40cfc8f3c28261e6f887b03"`);
await queryRunner.query(`DROP INDEX "IDX_8e4eb51a35d81b64dda28eed0a"`);
await queryRunner.query(`DROP TABLE "log"`);
await queryRunner.query(`DROP TYPE "log_level_enum"`);
}
}

View File

@@ -0,0 +1,29 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class webauthn1561706992953 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "attestation_challenge" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "challenge" character varying(64) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "registrationChallenge" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_d0ba6786e093f1bcb497572a6b5" PRIMARY KEY ("id", "userId"))`);
await queryRunner.query(`CREATE INDEX "IDX_f1a461a618fa1755692d0e0d59" ON "attestation_challenge" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_47efb914aed1f72dd39a306c7b" ON "attestation_challenge" ("challenge") `);
await queryRunner.query(`CREATE TABLE "user_security_key" ("id" character varying NOT NULL, "userId" character varying(32) NOT NULL, "publicKey" character varying NOT NULL, "lastUsed" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(30) NOT NULL, CONSTRAINT "PK_3e508571121ab39c5f85d10c166" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_ff9ca3b5f3ee3d0681367a9b44" ON "user_security_key" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_0d7718e562dcedd0aa5cf2c9f7" ON "user_security_key" ("publicKey") `);
await queryRunner.query(`ALTER TABLE "user_profile" ADD "securityKeysAvailable" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "attestation_challenge" ADD CONSTRAINT "FK_f1a461a618fa1755692d0e0d592" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_security_key" ADD CONSTRAINT "FK_ff9ca3b5f3ee3d0681367a9b447" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_security_key" DROP CONSTRAINT "FK_ff9ca3b5f3ee3d0681367a9b447"`);
await queryRunner.query(`ALTER TABLE "attestation_challenge" DROP CONSTRAINT "FK_f1a461a618fa1755692d0e0d592"`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "securityKeysAvailable"`);
await queryRunner.query(`DROP INDEX "IDX_0d7718e562dcedd0aa5cf2c9f7"`);
await queryRunner.query(`DROP INDEX "IDX_ff9ca3b5f3ee3d0681367a9b44"`);
await queryRunner.query(`DROP TABLE "user_security_key"`);
await queryRunner.query(`DROP INDEX "IDX_47efb914aed1f72dd39a306c7b"`);
await queryRunner.query(`DROP INDEX "IDX_f1a461a618fa1755692d0e0d59"`);
await queryRunner.query(`DROP TABLE "attestation_challenge"`);
}
}

View File

@@ -0,0 +1,201 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class ChartIndexes1561873850023 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc" ON "__chart__active_users" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_15e91a03aeeac9dbccdf43fc06" ON "__chart__active_users" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_00ed5f86db1f7efafb1978bf21" ON "__chart__active_users" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_20f57cc8f142c131340ee16742" ON "__chart__active_users" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_9a3ed15a30ab7e3a37702e6e08" ON "__chart__active_users" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_c26e2c1cbb6e911e0554b27416" ON "__chart__active_users" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_13565815f618a1ff53886c5b28" ON "__chart__drive" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_3fa0d0f17ca72e3dc80999a032" ON "__chart__drive" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_7a170f67425e62a8fabb76c872" ON "__chart__drive" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_6e1df243476e20cbf86572ecc0" ON "__chart__drive" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_3313d7288855ec105b5bbf6c21" ON "__chart__drive" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_06690fc959f1c9fdaf21928222" ON "__chart__drive" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_36cb699c49580d4e6c2e6159f9" ON "__chart__federation" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_e447064455928cf627590ef527" ON "__chart__federation" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_76e87c7bfc5d925fcbba405d84" ON "__chart__federation" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_2d416e6af791a82e338c79d480" ON "__chart__federation" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_dd907becf76104e4b656659e6b" ON "__chart__federation" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_e9cd07672b37d8966cf3709283" ON "__chart__federation" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_07747a1038c05f532a718fe1de" ON "__chart__hashtag" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_fcc181fb8283009c61cc4083ef" ON "__chart__hashtag" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_99a7d2faaef84a6f728d714ad6" ON "__chart__hashtag" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_49975586f50ed7b800fdd88fbd" ON "__chart__hashtag" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_25a97c02003338124b2b75fdbc" ON "__chart__hashtag" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_6d6f156ceefc6bc5f273a0e370" ON "__chart__hashtag" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_6b8f34a1a64b06014b6fb66824" ON "__chart__instance" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_c12f0af4a66cdd30c2287ce8aa" ON "__chart__instance" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63" ON "__chart__instance" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_d0a4f79af5a97b08f37b547197" ON "__chart__instance" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_39ee857ab2f23493037c6b6631" ON "__chart__instance" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_f5448d9633cff74208d850aabe" ON "__chart__instance" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_a1efd3e0048a5f2793a47360dc" ON "__chart__network" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_f8dd01baeded2ffa833e0a610a" ON "__chart__network" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_7b5da130992ec9df96712d4290" ON "__chart__network" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_08fac0eb3b11f04c200c0b40dd" ON "__chart__network" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_0a905b992fecd2b5c3fb98759e" ON "__chart__network" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_9ff6944f01acb756fdc92d7563" ON "__chart__network" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_42eb716a37d381cdf566192b2b" ON "__chart__notes" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_e69096589f11e3baa98ddd64d0" ON "__chart__notes" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_7036f2957151588b813185c794" ON "__chart__notes" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_0c9a159c5082cbeef3ca6706b5" ON "__chart__notes" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_f09d543e3acb16c5976bdb31fa" ON "__chart__notes" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_924fc196c80ca24bae01dd37e4" ON "__chart__notes" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_5f86db6492274e07c1a3cdf286" ON "__chart__per_user_drive" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_328f259961e60c4fa0bfcf55ca" ON "__chart__per_user_drive" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_e496ca8096d28f6b9b509264dc" ON "__chart__per_user_drive" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_42ea9381f0fda8dfe0fa1c8b53" ON "__chart__per_user_drive" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_30bf67687f483ace115c5ca642" ON "__chart__per_user_drive" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_f2aeafde2ae6fbad38e857631b" ON "__chart__per_user_drive" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7af07790712aa3438ff6773f3b" ON "__chart__per_user_following" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_f92dd6d03f8d994f29987f6214" ON "__chart__per_user_following" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_4b3593098b6edc9c5afe36b18b" ON "__chart__per_user_following" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_57b5458d0d3d6d1e7f13d4e57f" ON "__chart__per_user_following" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_b77d4dd9562c3a899d9a286fcd" ON "__chart__per_user_following" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_4db3b84c7be0d3464714f3e0b1" ON "__chart__per_user_following" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_84234bd1abb873f07329681c83" ON "__chart__per_user_notes" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_8d2cbbc8114d90d19b44d626b6" ON "__chart__per_user_notes" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_55bf20f366979f2436de99206b" ON "__chart__per_user_notes" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_046feeb12e9ef5f783f409866a" ON "__chart__per_user_notes" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_5048e9daccbbbc6d567bb142d3" ON "__chart__per_user_notes" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_f68a5ab958f9f5fa17a32ac23b" ON "__chart__per_user_notes" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_f7bf4c62059764c2c2bb40fdab" ON "__chart__per_user_reaction" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_65633a106bce43fc7c5c30a5c7" ON "__chart__per_user_reaction" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_8cf3156fd7a6b15c43459c6e3b" ON "__chart__per_user_reaction" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_edeb73c09c3143a81bcb34d569" ON "__chart__per_user_reaction" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_229a41ad465f9205f1f5703291" ON "__chart__per_user_reaction" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_e316f01a6d24eb31db27f88262" ON "__chart__per_user_reaction" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_0c641990ecf47d2545df4edb75" ON "__chart__test_grouped" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_2be7ec6cebddc14dc11e206686" ON "__chart__test_grouped" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_234dff3c0b56a6150b95431ab9" ON "__chart__test_grouped" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_a5133470f4825902e170328ca5" ON "__chart__test_grouped" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_b14489029e4b3aaf4bba5fb524" ON "__chart__test_grouped" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_84e661abb7bd1e51b690d4b017" ON "__chart__test_grouped" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_437bab3c6061d90f6bb65fd2cc" ON "__chart__test_unique" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_5c73bf61da4f6e6f15bae88ed1" ON "__chart__test_unique" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_bbfa573a8181018851ed0b6357" ON "__chart__test_unique" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_d70c86baedc68326be11f9c0ce" ON "__chart__test_unique" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_a0cd75442dd10d0643a17c4a49" ON "__chart__test_unique" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_66e1e1ecd2f29e57778af35b59" ON "__chart__test_unique" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_b070a906db04b44c67c6c2144d" ON "__chart__test" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_92255988735563f0fe4aba1f05" ON "__chart__test" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_d41cce6aee1a50bfc062038f9b" ON "__chart__test" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_c5870993e25c3d5771f91f5003" ON "__chart__test" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_a319e5dbf47e8a17497623beae" ON "__chart__test" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_f170de677ea75ad4533de2723e" ON "__chart__test" ("span", "date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_845254b3eaf708ae8a6cac3026" ON "__chart__users" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_7c184198ecf66a8d3ecb253ab3" ON "__chart__users" ("span") `);
await queryRunner.query(`CREATE INDEX "IDX_ed9b95919c672a13008e9487ee" ON "__chart__users" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_f091abb24193d50c653c6b77fc" ON "__chart__users" ("span", "date") `);
await queryRunner.query(`CREATE INDEX "IDX_337e9599f278bd7537fe30876f" ON "__chart__users" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_a770a57c70e668cc61590c9161" ON "__chart__users" ("span", "date", "group") `);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_a770a57c70e668cc61590c9161"`);
await queryRunner.query(`DROP INDEX "IDX_337e9599f278bd7537fe30876f"`);
await queryRunner.query(`DROP INDEX "IDX_f091abb24193d50c653c6b77fc"`);
await queryRunner.query(`DROP INDEX "IDX_ed9b95919c672a13008e9487ee"`);
await queryRunner.query(`DROP INDEX "IDX_7c184198ecf66a8d3ecb253ab3"`);
await queryRunner.query(`DROP INDEX "IDX_845254b3eaf708ae8a6cac3026"`);
await queryRunner.query(`DROP INDEX "IDX_f170de677ea75ad4533de2723e"`);
await queryRunner.query(`DROP INDEX "IDX_a319e5dbf47e8a17497623beae"`);
await queryRunner.query(`DROP INDEX "IDX_c5870993e25c3d5771f91f5003"`);
await queryRunner.query(`DROP INDEX "IDX_d41cce6aee1a50bfc062038f9b"`);
await queryRunner.query(`DROP INDEX "IDX_92255988735563f0fe4aba1f05"`);
await queryRunner.query(`DROP INDEX "IDX_b070a906db04b44c67c6c2144d"`);
await queryRunner.query(`DROP INDEX "IDX_66e1e1ecd2f29e57778af35b59"`);
await queryRunner.query(`DROP INDEX "IDX_a0cd75442dd10d0643a17c4a49"`);
await queryRunner.query(`DROP INDEX "IDX_d70c86baedc68326be11f9c0ce"`);
await queryRunner.query(`DROP INDEX "IDX_bbfa573a8181018851ed0b6357"`);
await queryRunner.query(`DROP INDEX "IDX_5c73bf61da4f6e6f15bae88ed1"`);
await queryRunner.query(`DROP INDEX "IDX_437bab3c6061d90f6bb65fd2cc"`);
await queryRunner.query(`DROP INDEX "IDX_84e661abb7bd1e51b690d4b017"`);
await queryRunner.query(`DROP INDEX "IDX_b14489029e4b3aaf4bba5fb524"`);
await queryRunner.query(`DROP INDEX "IDX_a5133470f4825902e170328ca5"`);
await queryRunner.query(`DROP INDEX "IDX_234dff3c0b56a6150b95431ab9"`);
await queryRunner.query(`DROP INDEX "IDX_2be7ec6cebddc14dc11e206686"`);
await queryRunner.query(`DROP INDEX "IDX_0c641990ecf47d2545df4edb75"`);
await queryRunner.query(`DROP INDEX "IDX_e316f01a6d24eb31db27f88262"`);
await queryRunner.query(`DROP INDEX "IDX_229a41ad465f9205f1f5703291"`);
await queryRunner.query(`DROP INDEX "IDX_edeb73c09c3143a81bcb34d569"`);
await queryRunner.query(`DROP INDEX "IDX_8cf3156fd7a6b15c43459c6e3b"`);
await queryRunner.query(`DROP INDEX "IDX_65633a106bce43fc7c5c30a5c7"`);
await queryRunner.query(`DROP INDEX "IDX_f7bf4c62059764c2c2bb40fdab"`);
await queryRunner.query(`DROP INDEX "IDX_f68a5ab958f9f5fa17a32ac23b"`);
await queryRunner.query(`DROP INDEX "IDX_5048e9daccbbbc6d567bb142d3"`);
await queryRunner.query(`DROP INDEX "IDX_046feeb12e9ef5f783f409866a"`);
await queryRunner.query(`DROP INDEX "IDX_55bf20f366979f2436de99206b"`);
await queryRunner.query(`DROP INDEX "IDX_8d2cbbc8114d90d19b44d626b6"`);
await queryRunner.query(`DROP INDEX "IDX_84234bd1abb873f07329681c83"`);
await queryRunner.query(`DROP INDEX "IDX_4db3b84c7be0d3464714f3e0b1"`);
await queryRunner.query(`DROP INDEX "IDX_b77d4dd9562c3a899d9a286fcd"`);
await queryRunner.query(`DROP INDEX "IDX_57b5458d0d3d6d1e7f13d4e57f"`);
await queryRunner.query(`DROP INDEX "IDX_4b3593098b6edc9c5afe36b18b"`);
await queryRunner.query(`DROP INDEX "IDX_f92dd6d03f8d994f29987f6214"`);
await queryRunner.query(`DROP INDEX "IDX_7af07790712aa3438ff6773f3b"`);
await queryRunner.query(`DROP INDEX "IDX_f2aeafde2ae6fbad38e857631b"`);
await queryRunner.query(`DROP INDEX "IDX_30bf67687f483ace115c5ca642"`);
await queryRunner.query(`DROP INDEX "IDX_42ea9381f0fda8dfe0fa1c8b53"`);
await queryRunner.query(`DROP INDEX "IDX_e496ca8096d28f6b9b509264dc"`);
await queryRunner.query(`DROP INDEX "IDX_328f259961e60c4fa0bfcf55ca"`);
await queryRunner.query(`DROP INDEX "IDX_5f86db6492274e07c1a3cdf286"`);
await queryRunner.query(`DROP INDEX "IDX_924fc196c80ca24bae01dd37e4"`);
await queryRunner.query(`DROP INDEX "IDX_f09d543e3acb16c5976bdb31fa"`);
await queryRunner.query(`DROP INDEX "IDX_0c9a159c5082cbeef3ca6706b5"`);
await queryRunner.query(`DROP INDEX "IDX_7036f2957151588b813185c794"`);
await queryRunner.query(`DROP INDEX "IDX_e69096589f11e3baa98ddd64d0"`);
await queryRunner.query(`DROP INDEX "IDX_42eb716a37d381cdf566192b2b"`);
await queryRunner.query(`DROP INDEX "IDX_9ff6944f01acb756fdc92d7563"`);
await queryRunner.query(`DROP INDEX "IDX_0a905b992fecd2b5c3fb98759e"`);
await queryRunner.query(`DROP INDEX "IDX_08fac0eb3b11f04c200c0b40dd"`);
await queryRunner.query(`DROP INDEX "IDX_7b5da130992ec9df96712d4290"`);
await queryRunner.query(`DROP INDEX "IDX_f8dd01baeded2ffa833e0a610a"`);
await queryRunner.query(`DROP INDEX "IDX_a1efd3e0048a5f2793a47360dc"`);
await queryRunner.query(`DROP INDEX "IDX_f5448d9633cff74208d850aabe"`);
await queryRunner.query(`DROP INDEX "IDX_39ee857ab2f23493037c6b6631"`);
await queryRunner.query(`DROP INDEX "IDX_d0a4f79af5a97b08f37b547197"`);
await queryRunner.query(`DROP INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63"`);
await queryRunner.query(`DROP INDEX "IDX_c12f0af4a66cdd30c2287ce8aa"`);
await queryRunner.query(`DROP INDEX "IDX_6b8f34a1a64b06014b6fb66824"`);
await queryRunner.query(`DROP INDEX "IDX_6d6f156ceefc6bc5f273a0e370"`);
await queryRunner.query(`DROP INDEX "IDX_25a97c02003338124b2b75fdbc"`);
await queryRunner.query(`DROP INDEX "IDX_49975586f50ed7b800fdd88fbd"`);
await queryRunner.query(`DROP INDEX "IDX_99a7d2faaef84a6f728d714ad6"`);
await queryRunner.query(`DROP INDEX "IDX_fcc181fb8283009c61cc4083ef"`);
await queryRunner.query(`DROP INDEX "IDX_07747a1038c05f532a718fe1de"`);
await queryRunner.query(`DROP INDEX "IDX_e9cd07672b37d8966cf3709283"`);
await queryRunner.query(`DROP INDEX "IDX_dd907becf76104e4b656659e6b"`);
await queryRunner.query(`DROP INDEX "IDX_2d416e6af791a82e338c79d480"`);
await queryRunner.query(`DROP INDEX "IDX_76e87c7bfc5d925fcbba405d84"`);
await queryRunner.query(`DROP INDEX "IDX_e447064455928cf627590ef527"`);
await queryRunner.query(`DROP INDEX "IDX_36cb699c49580d4e6c2e6159f9"`);
await queryRunner.query(`DROP INDEX "IDX_06690fc959f1c9fdaf21928222"`);
await queryRunner.query(`DROP INDEX "IDX_3313d7288855ec105b5bbf6c21"`);
await queryRunner.query(`DROP INDEX "IDX_6e1df243476e20cbf86572ecc0"`);
await queryRunner.query(`DROP INDEX "IDX_7a170f67425e62a8fabb76c872"`);
await queryRunner.query(`DROP INDEX "IDX_3fa0d0f17ca72e3dc80999a032"`);
await queryRunner.query(`DROP INDEX "IDX_13565815f618a1ff53886c5b28"`);
await queryRunner.query(`DROP INDEX "IDX_c26e2c1cbb6e911e0554b27416"`);
await queryRunner.query(`DROP INDEX "IDX_9a3ed15a30ab7e3a37702e6e08"`);
await queryRunner.query(`DROP INDEX "IDX_20f57cc8f142c131340ee16742"`);
await queryRunner.query(`DROP INDEX "IDX_00ed5f86db1f7efafb1978bf21"`);
await queryRunner.query(`DROP INDEX "IDX_15e91a03aeeac9dbccdf43fc06"`);
await queryRunner.query(`DROP INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc"`);
await queryRunner.query(`DROP INDEX "IDX_90148bbc2bf0854428786bfc15"`);
await queryRunner.query(`DROP INDEX "IDX_88937d94d7443d9a99a76fa5c0"`);
await queryRunner.query(`DROP INDEX "IDX_54ebcb6d27222913b908d56fd8"`);
await queryRunner.query(`DROP INDEX "IDX_796a8c03959361f97dc2be1d5c"`);
await queryRunner.query(`DROP INDEX "IDX_25dfc71b0369b003a4cd434d0b"`);
await queryRunner.query(`DROP INDEX "IDX_51c063b6a133a9cb87145450f5"`);
await queryRunner.query(`DROP INDEX "IDX_fa99d777623947a5b05f394cae"`);
await queryRunner.query(`DROP INDEX "IDX_315c779174fe8247ab324f036e"`);
await queryRunner.query(`DROP INDEX "IDX_c5d46cbfda48b1c33ed852e21b"`);
await queryRunner.query(`DROP INDEX "IDX_8cb40cfc8f3c28261e6f887b03"`);
}
}

View File

@@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class PasswordLessLogin1562422242907 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "usePasswordLessLogin" boolean DEFAULT false NOT NULL`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "usePasswordLessLogin"`);
}
}

View File

@@ -0,0 +1,17 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class PinnedPage1562444565093 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" ADD "pinnedPageId" character varying(32)`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "UQ_6dc44f1ceb65b1e72bacef2ca27" UNIQUE ("pinnedPageId")`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "FK_6dc44f1ceb65b1e72bacef2ca27" FOREIGN KEY ("pinnedPageId") REFERENCES "page"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "FK_6dc44f1ceb65b1e72bacef2ca27"`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "UQ_6dc44f1ceb65b1e72bacef2ca27"`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "pinnedPageId"`);
}
}

View File

@@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class PageTitleHideOption1562448332510 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "page" ADD "hideTitleWhenPinned" boolean NOT NULL DEFAULT false`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "hideTitleWhenPinned"`);
}
}

View File

@@ -1,7 +1,7 @@
import * as fs from 'fs'; const config = require('./built/config').default;
import config from './config'; const entities = require('./built/db/postgre').entities;
const json = { module.exports = {
type: 'postgres', type: 'postgres',
host: config.db.host, host: config.db.host,
port: config.db.port, port: config.db.port,
@@ -9,11 +9,9 @@ const json = {
password: config.db.pass, password: config.db.pass,
database: config.db.db, database: config.db.db,
extra: config.db.extra, extra: config.db.extra,
entities: ['src/models/entities/*.ts'], entities: entities,
migrations: ['migration/*.ts'], migrations: ['migration/*.ts'],
cli: { cli: {
migrationsDir: 'migration' migrationsDir: 'migration'
} }
}; };
fs.writeFileSync('ormconfig.json', JSON.stringify(json));

View File

@@ -1,7 +1,7 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "11.20.3", "version": "11.25.1",
"codename": "daybreak", "codename": "daybreak",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -11,9 +11,9 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node ./index.js", "start": "node ./index.js",
"init": "node ./built/init.js", "init": "npm run migrate",
"ormconfig": "node ./built/ormconfig.js", "ormconfig": "node ./built/ormconfig.js",
"migrate": "npm run ormconfig && ts-node ./node_modules/typeorm/cli.js migration:run", "migrate": "ts-node ./node_modules/typeorm/cli.js migration:run",
"migrateandstart": "npm run migrate && npm run start", "migrateandstart": "npm run migrate && npm run start",
"build": "webpack && gulp build", "build": "webpack && gulp build",
"webpack": "webpack", "webpack": "webpack",
@@ -30,105 +30,109 @@
"video-thumbnail-generator/lodash": "^4.17.11" "video-thumbnail-generator/lodash": "^4.17.11"
}, },
"dependencies": { "dependencies": {
"@elastic/elasticsearch": "7.0.0-rc.2", "@elastic/elasticsearch": "7.1.0",
"@fortawesome/fontawesome-svg-core": "1.2.15", "@fortawesome/fontawesome-svg-core": "1.2.19",
"@fortawesome/free-brands-svg-icons": "5.7.2", "@fortawesome/free-brands-svg-icons": "5.9.0",
"@fortawesome/free-regular-svg-icons": "5.7.2", "@fortawesome/free-regular-svg-icons": "5.9.0",
"@fortawesome/free-solid-svg-icons": "5.7.2", "@fortawesome/free-solid-svg-icons": "5.9.0",
"@fortawesome/vue-fontawesome": "0.1.5", "@fortawesome/vue-fontawesome": "0.1.6",
"@koa/cors": "2.2.3", "@koa/cors": "3.0.0",
"@typescript-eslint/parser": "1.11.0",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/bull": "3.5.11", "@types/bull": "3.5.15",
"@types/cbor": "2.0.0",
"@types/dateformat": "3.0.0", "@types/dateformat": "3.0.0",
"@types/deep-equal": "1.0.1", "@types/deep-equal": "1.0.1",
"@types/double-ended-queue": "2.1.0", "@types/double-ended-queue": "2.1.1",
"@types/gulp": "4.0.6", "@types/gulp": "4.0.6",
"@types/gulp-mocha": "0.0.32", "@types/gulp-mocha": "0.0.32",
"@types/gulp-rename": "0.0.33", "@types/gulp-rename": "0.0.33",
"@types/gulp-replace": "0.0.31", "@types/gulp-replace": "0.0.31",
"@types/gulp-uglify": "3.0.6", "@types/gulp-uglify": "3.0.6",
"@types/gulp-util": "3.0.34", "@types/gulp-util": "3.0.34",
"@types/is-root": "1.0.0", "@types/is-root": "2.1.2",
"@types/is-url": "1.2.28", "@types/is-url": "1.2.28",
"@types/js-yaml": "3.12.1", "@types/js-yaml": "3.12.1",
"@types/jsdom": "12.2.3", "@types/jsdom": "12.2.4",
"@types/katex": "0.10.1", "@types/katex": "0.10.1",
"@types/koa": "2.0.48", "@types/koa": "2.0.49",
"@types/koa-bodyparser": "5.0.2", "@types/koa-bodyparser": "5.0.2",
"@types/koa-compress": "2.0.9", "@types/koa-compress": "2.0.9",
"@types/koa-cors": "0.0.0", "@types/koa-cors": "0.0.0",
"@types/koa-favicon": "2.0.19", "@types/koa-favicon": "2.0.19",
"@types/koa-logger": "3.1.1", "@types/koa-logger": "3.1.1",
"@types/koa-mount": "3.0.1", "@types/koa-mount": "4.0.0",
"@types/koa-multer": "1.0.0", "@types/koa-multer": "1.0.0",
"@types/koa-router": "7.0.40", "@types/koa-router": "7.0.42",
"@types/koa-send": "4.1.2", "@types/koa-send": "4.1.2",
"@types/koa-views": "2.0.3", "@types/koa-views": "2.0.3",
"@types/koa__cors": "2.2.3", "@types/koa__cors": "2.2.3",
"@types/lolex": "3.1.1", "@types/lolex": "3.1.1",
"@types/minio": "7.0.1", "@types/minio": "7.0.2",
"@types/mocha": "5.2.6", "@types/mocha": "5.2.7",
"@types/node": "11.13.8", "@types/node": "12.0.10",
"@types/nodemailer": "4.6.8", "@types/nodemailer": "6.2.0",
"@types/nprogress": "0.0.29", "@types/nprogress": "0.2.0",
"@types/oauth": "0.9.1", "@types/oauth": "0.9.1",
"@types/parse5": "5.0.0", "@types/parse5": "5.0.0",
"@types/parsimmon": "1.10.0", "@types/parsimmon": "1.10.0",
"@types/portscanner": "2.1.0", "@types/portscanner": "2.1.0",
"@types/pug": "2.0.4", "@types/pug": "2.0.4",
"@types/qrcode": "1.3.2", "@types/qrcode": "1.3.3",
"@types/random-seed": "0.3.3", "@types/random-seed": "0.3.3",
"@types/ratelimiter": "2.1.28", "@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.12", "@types/redis": "2.8.13",
"@types/rename": "1.0.1", "@types/rename": "1.0.1",
"@types/request": "2.48.1", "@types/request": "2.48.1",
"@types/request-promise-native": "1.0.16", "@types/request-promise-native": "1.0.16",
"@types/request-stats": "3.0.0", "@types/request-stats": "3.0.0",
"@types/rimraf": "2.0.2", "@types/rimraf": "2.0.2",
"@types/seedrandom": "2.4.28", "@types/seedrandom": "2.4.28",
"@types/sharp": "0.22.1", "@types/sharp": "0.22.2",
"@types/showdown": "1.9.2", "@types/showdown": "1.9.3",
"@types/speakeasy": "2.0.4", "@types/speakeasy": "2.0.4",
"@types/systeminformation": "3.23.1", "@types/systeminformation": "3.23.1",
"@types/tinycolor2": "1.4.1", "@types/tinycolor2": "1.4.2",
"@types/tmp": "0.1.0", "@types/tmp": "0.1.0",
"@types/uuid": "3.4.4", "@types/uuid": "3.4.5",
"@types/web-push": "3.3.0", "@types/web-push": "3.3.0",
"@types/webpack": "4.4.29", "@types/webpack": "4.4.34",
"@types/webpack-stream": "3.2.10", "@types/webpack-stream": "3.2.10",
"@types/websocket": "0.0.40", "@types/websocket": "0.0.40",
"@types/ws": "6.0.1", "@types/ws": "6.0.1",
"animejs": "3.0.1", "animejs": "3.0.1",
"apexcharts": "3.7.1", "apexcharts": "3.8.1",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autosize": "4.0.2", "autosize": "4.0.2",
"autwh": "0.1.0", "autwh": "0.1.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"bootstrap": "4.3.1",
"bootstrap-vue": "2.0.0-rc.13", "bootstrap-vue": "2.0.0-rc.13",
"bull": "3.10.0", "bull": "3.10.0",
"cafy": "15.1.1", "cafy": "15.1.1",
"cbor": "4.1.5",
"chai": "4.2.0", "chai": "4.2.0",
"chalk": "2.4.2", "chalk": "2.4.2",
"cli-highlight": "2.1.1", "cli-highlight": "2.1.1",
"commander": "2.20.0", "commander": "2.20.0",
"content-disposition": "0.5.3", "content-disposition": "0.5.3",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "2.1.1", "css-loader": "3.0.0",
"cssnano": "4.1.10", "cssnano": "4.1.10",
"dateformat": "3.0.3", "dateformat": "3.0.3",
"deep-equal": "1.0.1", "deep-equal": "1.0.1",
"diskusage": "1.1.1", "diskusage": "1.1.2",
"double-ended-queue": "2.1.0-0", "double-ended-queue": "2.1.0-0",
"emojilib": "2.4.0", "emojilib": "2.4.0",
"eslint": "5.16.0", "eslint": "6.0.1",
"eslint-plugin-vue": "5.2.2", "eslint-plugin-vue": "5.2.3",
"eventemitter3": "3.1.2", "eventemitter3": "4.0.0",
"feed": "2.0.4", "feed": "3.0.0",
"file-type": "10.11.0", "file-type": "12.0.0",
"fuckadblock": "3.2.1", "fuckadblock": "3.2.1",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-cssnano": "2.1.3", "gulp-cssnano": "2.1.3",
"gulp-imagemin": "5.0.3", "gulp-imagemin": "6.0.0",
"gulp-mocha": "6.0.0", "gulp-mocha": "6.0.0",
"gulp-rename": "1.4.0", "gulp-rename": "1.4.0",
"gulp-replace": "1.0.0", "gulp-replace": "1.0.0",
@@ -147,7 +151,8 @@
"js-yaml": "3.13.1", "js-yaml": "3.13.1",
"jsdom": "15.1.1", "jsdom": "15.1.1",
"json5": "2.1.0", "json5": "2.1.0",
"json5-loader": "2.0.0", "json5-loader": "3.0.0",
"jsrsasign": "8.0.12",
"katex": "0.10.2", "katex": "0.10.2",
"koa": "2.7.0", "koa": "2.7.0",
"koa-bodyparser": "4.2.1", "koa-bodyparser": "4.2.1",
@@ -163,14 +168,14 @@
"koa-views": "6.2.0", "koa-views": "6.2.0",
"langmap": "0.0.16", "langmap": "0.0.16",
"loader-utils": "1.2.3", "loader-utils": "1.2.3",
"lolex": "3.1.0", "lolex": "4.1.0",
"lookup-dns-cache": "2.1.0", "lookup-dns-cache": "2.1.0",
"minio": "7.0.8", "minio": "7.0.10",
"mocha": "6.1.4", "mocha": "6.1.4",
"moji": "0.5.1", "moji": "0.5.1",
"moment": "2.24.0", "moment": "2.24.0",
"ms": "2.1.1", "ms": "2.1.2",
"nested-property": "0.0.7", "nested-property": "1.0.1",
"node-fetch": "2.6.0", "node-fetch": "2.6.0",
"nodemailer": "6.2.1", "nodemailer": "6.2.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
@@ -186,7 +191,7 @@
"promise-any": "0.2.0", "promise-any": "0.2.0",
"promise-limit": "2.7.0", "promise-limit": "2.7.0",
"promise-sequential": "1.1.1", "promise-sequential": "1.1.1",
"pug": "2.0.3", "pug": "2.0.4",
"punycode": "2.1.1", "punycode": "2.1.1",
"pureimage": "0.1.6", "pureimage": "0.1.6",
"qrcode": "1.3.3", "qrcode": "1.3.3",
@@ -210,12 +215,12 @@
"showdown": "1.9.0", "showdown": "1.9.0",
"showdown-highlightjs-extension": "0.1.2", "showdown-highlightjs-extension": "0.1.2",
"speakeasy": "2.0.0", "speakeasy": "2.0.0",
"stringz": "1.0.0", "stringz": "2.0.0",
"style-loader": "0.23.1", "style-loader": "0.23.1",
"stylus": "0.54.5", "stylus": "0.54.5",
"stylus-loader": "3.0.2", "stylus-loader": "3.0.2",
"summaly": "2.2.0", "summaly": "2.3.0",
"systeminformation": "4.1.6", "systeminformation": "4.13.1",
"syuilo-password-strength": "0.0.1", "syuilo-password-strength": "0.0.1",
"terser-webpack-plugin": "1.3.0", "terser-webpack-plugin": "1.3.0",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
@@ -223,14 +228,13 @@
"tmp": "0.1.0", "tmp": "0.1.0",
"ts-loader": "5.3.3", "ts-loader": "5.3.3",
"ts-node": "7.0.1", "ts-node": "7.0.1",
"tslint": "5.15.0", "tslint": "5.18.0",
"tslint-sonarts": "1.9.0", "tslint-sonarts": "1.9.0",
"typeorm": "0.2.16-rc.1", "typeorm": "0.2.18",
"typescript": "3.3.3333", "typescript": "3.5.2",
"typescript-eslint-parser": "22.0.0",
"uglify-es": "3.3.9", "uglify-es": "3.3.9",
"ulid": "2.3.0", "ulid": "2.3.0",
"url-loader": "1.1.2", "url-loader": "2.0.1",
"uuid": "3.3.2", "uuid": "3.3.2",
"v-animate-css": "0.0.3", "v-animate-css": "0.0.3",
"v-debounce": "0.1.2", "v-debounce": "0.1.2",
@@ -238,7 +242,7 @@
"vue": "2.6.10", "vue": "2.6.10",
"vue-color": "2.7.0", "vue-color": "2.7.0",
"vue-content-loading": "1.6.0", "vue-content-loading": "1.6.0",
"vue-cropperjs": "3.0.0", "vue-cropperjs": "4.0.0",
"vue-i18n": "8.11.2", "vue-i18n": "8.11.2",
"vue-js-modal": "1.3.31", "vue-js-modal": "1.3.31",
"vue-json-pretty": "1.6.0", "vue-json-pretty": "1.6.0",
@@ -248,17 +252,17 @@
"vue-router": "3.0.6", "vue-router": "3.0.6",
"vue-sequential-entrance": "1.1.3", "vue-sequential-entrance": "1.1.3",
"vue-style-loader": "4.1.2", "vue-style-loader": "4.1.2",
"vue-svg-inline-loader": "1.2.15", "vue-svg-inline-loader": "1.2.16",
"vue-template-compiler": "2.6.10", "vue-template-compiler": "2.6.10",
"vuedraggable": "2.21.0", "vuedraggable": "2.23.0",
"vuewordcloud": "18.7.11", "vuewordcloud": "18.7.11",
"vuex": "3.1.1", "vuex": "3.1.1",
"vuex-persistedstate": "2.5.4", "vuex-persistedstate": "2.5.4",
"web-push": "3.3.5", "web-push": "3.3.5",
"webpack": "4.33.0", "webpack": "4.35.2",
"webpack-cli": "3.3.2", "webpack-cli": "3.3.5",
"websocket": "1.0.28", "websocket": "1.0.28",
"ws": "7.0.0", "ws": "7.0.1",
"xev": "2.0.1" "xev": "2.0.1"
} }
} }

803
src/@types/jsrsasign.d.ts vendored Normal file
View File

@@ -0,0 +1,803 @@
// Attention: Partial Type Definition
declare module 'jsrsasign' {
//// HELPER TYPES
/**
* Attention: The value might be changed by the function.
*/
type Mutable<T> = T;
/**
* Deprecated: The function might be deleted in future release.
*/
type Deprecated<T> = T;
//// COMMON TYPES
/**
* byte number
*/
type ByteNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255;
/**
* hexadecimal string /[0-9A-F]/
*/
type HexString = string;
/**
* binary string /[01]/
*/
type BinString = string;
/**
* base64 string /[A-Za-z0-9+/]=+/
*/
type Base64String = string;
/**
* base64 URL encoded string /[A-Za-z0-9_-]/
*/
type Base64URLString = string;
/**
* time value (ex. "151231235959Z")
*/
type TimeValue = string;
/**
* OID string (ex. '1.2.3.4.567')
*/
type OID = string;
/**
* OID name
*/
type OIDName = string;
/**
* PEM formatted string
*/
type PEM = string;
//// ASN1 TYPES
class ASN1Object {
public isModified: boolean;
public hTLV: ASN1TLV;
public hT: ASN1T;
public hL: ASN1L;
public hV: ASN1V;
public getLengthHexFromValue(): HexString;
public getEncodedHex(): ASN1TLV;
public getValueHex(): ASN1V;
public getFreshValueHex(): ASN1V;
}
class DERAbstractStructured extends ASN1Object {
constructor(params?: Partial<Record<'array', ASN1Object[]>>);
public setByASN1ObjectArray(asn1ObjectArray: ASN1Object[]): void;
public appendASN1Object(asn1Object: ASN1Object): void;
}
class DERSequence extends DERAbstractStructured {
constructor(params?: Partial<Record<'array', ASN1Object[]>>);
public getFreshValueHex(): ASN1V;
}
//// ASN1HEX TYPES
/**
* ASN.1 DER encoded data (hexadecimal string)
*/
type ASN1S = HexString;
/**
* index of something
*/
type Idx<T extends { [idx: string]: unknown } | { [idx: number]: unknown }> = ASN1S extends { [idx: string]: unknown } ? string : ASN1S extends { [idx: number]: unknown } ? number : never;
/**
* byte length of something
*/
type ByteLength<T extends { length: unknown }> = T['length'];
/**
* ASN.1 L(length) (hexadecimal string)
*/
type ASN1L = HexString;
/**
* ASN.1 T(tag) (hexadecimal string)
*/
type ASN1T = HexString;
/**
* ASN.1 V(value) (hexadecimal string)
*/
type ASN1V = HexString;
/**
* ASN.1 TLV (hexadecimal string)
*/
type ASN1TLV = HexString;
/**
* ASN.1 object string
*/
type ASN1ObjectString = string;
/**
* nth
*/
type Nth = number;
/**
* ASN.1 DER encoded OID value (hexadecimal string)
*/
type ASN1OIDV = HexString;
class ASN1HEX {
public static getLblen(s: ASN1S, idx: Idx<ASN1S>): ByteLength<ASN1L>;
public static getL(s: ASN1S, idx: Idx<ASN1S>): ASN1L;
public static getVblen(s: ASN1S, idx: Idx<ASN1S>): ByteLength<ASN1V>;
public static getVidx(s: ASN1S, idx: Idx<ASN1S>): Idx<ASN1V>;
public static getV(s: ASN1S, idx: Idx<ASN1S>): ASN1V;
public static getTLV(s: ASN1S, idx: Idx<ASN1S>): ASN1TLV;
public static getNextSiblingIdx(s: ASN1S, idx: Idx<ASN1S>): Idx<ASN1ObjectString>;
public static getChildIdx(h: ASN1S, pos: Idx<ASN1S>): Idx<ASN1ObjectString>[];
public static getNthChildIdx(h: ASN1S, idx: Idx<ASN1S>, nth: Nth): Idx<ASN1ObjectString>;
public static getIdxbyList(h: ASN1S, currentIndex: Idx<ASN1ObjectString>, nthList: Mutable<Nth[]>, checkingTag?: string): Idx<Mutable<Nth[]>>;
public static getTLVbyList(h: ASN1S, currentIndex: Idx<ASN1ObjectString>, nthList: Mutable<Nth[]>, checkingTag?: string): ASN1TLV;
public static getVbyList(h: ASN1S, currentIndex: Idx<ASN1ObjectString>, nthList: Mutable<Nth[]>, checkingTag?: string, removeUnusedbits?: boolean): ASN1V;
public static hextooidstr(hex: ASN1OIDV): OID;
public static dump(hexOrObj: ASN1S | ASN1Object, flags?: Record<string, unknown>, idx?: Idx<ASN1S>, indent?: string): string;
public static isASN1HEX(hex: string): hex is HexString;
public static oidname(oidDotOrHex: OID | ASN1OIDV): OIDName;
}
//// BIG INTEGER TYPES (PARTIAL)
class BigInteger {
constructor(a: null);
constructor(a: number, b: SecureRandom);
constructor(a: number, b: number, c: SecureRandom);
constructor(a: unknown);
constructor(a: string, b: number);
public am(i: number, x: number, w: number, j: number, c: number, n: number): number;
public DB: number;
public DM: number;
public DV: number;
public FV: number;
public F1: number;
public F2: number;
protected copyTo(r: Mutable<BigInteger>): void;
protected fromInt(x: number): void;
protected fromString(s: string, b: number): void;
protected clamp(): void;
public toString(b: number): string;
public negate(): BigInteger;
public abs(): BigInteger;
public compareTo(a: BigInteger): number;
public bitLength(): number;
protected dlShiftTo(n: number, r: Mutable<BigInteger>): void;
protected drShiftTo(n: number, r: Mutable<BigInteger>): void;
protected lShiftTo(n: number, r: Mutable<BigInteger>): void;
protected rShiftTo(n: number, r: Mutable<BigInteger>): void;
protected subTo(a: BigInteger, r: Mutable<BigInteger>): void;
protected multiplyTo(a: BigInteger, r: Mutable<BigInteger>): void;
protected squareTo(r: Mutable<BigInteger>): void;
protected divRemTo(m: BigInteger, q: Mutable<BigInteger>, r: Mutable<BigInteger>): void;
public mod(a: BigInteger): BigInteger;
protected invDigit(): number;
protected isEven(): boolean;
protected exp(e: number, z: Classic | Montgomery): BigInteger;
public modPowInt(e: number, m: BigInteger): BigInteger;
public static ZERO: BigInteger;
public static ONE: BigInteger;
}
class Classic {
constructor(m: BigInteger);
public convert(x: BigInteger): BigInteger;
public revert(x: BigInteger): BigInteger;
public reduce(x: Mutable<BigInteger>): void;
public mulTo(x: BigInteger, r: Mutable<BigInteger>): void;
public sqrTo(x: BigInteger, y: BigInteger, r: Mutable<BigInteger>): void;
}
class Montgomery {
constructor(m: BigInteger);
public convert(x: BigInteger): BigInteger;
public revert(x: BigInteger): BigInteger;
public reduce(x: Mutable<BigInteger>): void;
public mulTo(x: BigInteger, r: Mutable<BigInteger>): void;
public sqrTo(x: BigInteger, y: BigInteger, r: Mutable<BigInteger>): void;
}
//// KEYUTIL TYPES
type DecryptAES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
type Decrypt3DES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
type DecryptDES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
type EncryptAES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
type Encrypt3DES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
type EncryptDES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
type AlgList = {
'AES-256-CBC': { 'proc': DecryptAES; 'eproc': EncryptAES; keylen: 32; ivlen: 16; };
'AES-192-CBC': { 'proc': DecryptAES; 'eproc': EncryptAES; keylen: 24; ivlen: 16; };
'AES-128-CBC': { 'proc': DecryptAES; 'eproc': EncryptAES; keylen: 16; ivlen: 16; };
'DES-EDE3-CBC': { 'proc': Decrypt3DES; 'eproc': Encrypt3DES; keylen: 24; ivlen: 8; };
'DES-CBC': { 'proc': DecryptDES; 'eproc': EncryptDES; keylen: 8; ivlen: 8; };
};
type AlgName = keyof AlgList;
type PEMHeadAlgName = 'RSA' | 'EC' | 'DSA';
type GetKeyRSAParam = RSAKey | {
n: BigInteger;
e: number;
} | Record<'n' | 'e', HexString> | Record<'n' | 'e', HexString> & Record<'d' | 'p' | 'q' | 'dp' | 'dq' | 'co', HexString | null> | {
n: BigInteger;
e: number;
d: BigInteger;
} | {
kty: 'RSA';
} & Record<'n' | 'e', Base64URLString> | {
kty: 'RSA';
} & Record<'n' | 'e' | 'd' | 'p' | 'q' | 'dp' | 'dq' | 'qi', Base64URLString> | {
kty: 'RSA';
} & Record<'n' | 'e' | 'd', Base64URLString>;
type GetKeyECDSAParam = KJUR.crypto.ECDSA | {
curve: KJUR.crypto.CurveName;
xy: HexString;
} | {
curve: KJUR.crypto.CurveName;
d: HexString;
} | {
kty: 'EC';
crv: KJUR.crypto.CurveName;
x: Base64URLString;
y: Base64URLString;
} | {
kty: 'EC';
crv: KJUR.crypto.CurveName;
x: Base64URLString;
y: Base64URLString;
d: Base64URLString;
};
type GetKeyDSAParam = KJUR.crypto.DSA | Record<'p' | 'q' | 'g', BigInteger> & Record<'y', BigInteger | null> | Record<'p' | 'q' | 'g' | 'x', BigInteger> & Record<'y', BigInteger | null>;
type GetKeyParam = GetKeyRSAParam | GetKeyECDSAParam | GetKeyDSAParam | string;
class KEYUTIL {
public version: '1.0.0';
public parsePKCS5PEM(sPKCS5PEM: PEM): Partial<Record<'type' | 's', string>> & (Record<'cipher' | 'ivsalt', string> | Record<'cipher' | 'ivsalt', undefined>);
public getKeyAndUnusedIvByPasscodeAndIvsalt(algName: AlgName, passcode: string, ivsaltHex: HexString): Record<'keyhex' | 'ivhex', HexString>;
public decryptKeyB64(privateKeyB64: Base64String, sharedKeyAlgName: AlgName, sharedKeyHex: HexString, ivsaltHex: HexString): Base64String;
public getDecryptedKeyHex(sEncryptedPEM: PEM, passcode: string): HexString;
public getEncryptedPKCS5PEMFromPrvKeyHex(pemHeadAlg: PEMHeadAlgName, hPrvKey: string, passcode: string, sharedKeyAlgName?: AlgName | null, ivsaltHex?: HexString | null): PEM;
public parseHexOfEncryptedPKCS8(sHEX: HexString): {
ciphertext: ASN1V;
encryptionSchemeAlg: 'TripleDES';
encryptionSchemeIV: ASN1V;
pbkdf2Salt: ASN1V;
pbkdf2Iter: number;
};
public getPBKDF2KeyHexFromParam(info: ReturnType<this['parseHexOfEncryptedPKCS8']>, passcode: string): HexString;
private _getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM: PEM, passcode: string): HexString;
public getKeyFromEncryptedPKCS8PEM(prvKeyHex: HexString): ReturnType<this['getKeyFromPlainPrivatePKCS8Hex']>;
public parsePlainPrivatePKCS8Hex(pkcs8PrvHex: HexString): {
algparam: ASN1V | null;
algoid: ASN1V;
keyidx: Idx<ASN1V>;
};
public getKeyFromPlainPrivatePKCS8PEM(prvKeyHex: HexString): ReturnType<this['getKeyFromPlainPrivatePKCS8Hex']>;
public getKeyFromPlainPrivatePKCS8Hex(prvKeyHex: HexString): RSAKey | KJUR.crypto.DSA | KJUR.crypto.ECDSA;
private _getKeyFromPublicPKCS8Hex(h: HexString): RSAKey | KJUR.crypto.DSA | KJUR.crypto.ECDSA;
public parsePublicRawRSAKeyHex(pubRawRSAHex: HexString): Record<'n' | 'e', ASN1V>;
public parsePublicPKCS8Hex(pkcs8PubHex: HexString): {
algparam: ASN1V | Record<'p' | 'q' | 'g', ASN1V> | null;
algoid: ASN1V;
key: ASN1V;
};
public static getKey(param: GetKeyRSAParam): RSAKey;
public static getKey(param: GetKeyECDSAParam): KJUR.crypto.ECDSA;
public static getKey(param: GetKeyDSAParam): KJUR.crypto.DSA;
public static getKey(param: string, passcode?: string, hextype?: string): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
public static generateKeypair(alg: 'RSA', keylen: number): Record<'prvKeyObj' | 'pubKeyObj', RSAKey>;
public static generateKeypair(alg: 'EC', curve: KJUR.crypto.CurveName): Record<'prvKeyObj' | 'pubKeyObj', KJUR.crypto.ECDSA>;
public static getPEM(keyObjOrHex: RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA, formatType?: 'PKCS1PRV' | 'PKCS5PRV' | 'PKCS8PRV', passwd?: string, encAlg?: 'DES-CBC' | 'DES-EDE3-CBC' | 'AES-128-CBC' | 'AES-192-CBC' | 'AES-256-CBC', hexType?: string, ivsaltHex?: HexString): object; // To Do
public static getKeyFromCSRPEM(csrPEM: PEM): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
public static getKeyFromCSRHex(csrHex: HexString): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
public static parseCSRHex(csrHex: HexString): Record<'p8pubkeyhex', ASN1TLV>;
public static getJWKFromKey(keyObj: RSAKey): {
kty: 'RSA';
} & Record<'n' | 'e' | 'd' | 'p' | 'q' | 'dp' | 'dq' | 'qi', Base64URLString> | {
kty: 'RSA';
} & Record<'n' | 'e', Base64URLString>;
public static getJWKFromKey(keyObj: KJUR.crypto.ECDSA): {
kty: 'EC';
crv: KJUR.crypto.CurveName;
x: Base64URLString;
y: Base64URLString;
d: Base64URLString;
} | {
kty: 'EC';
crv: KJUR.crypto.CurveName;
x: Base64URLString;
y: Base64URLString;
};
}
//// KJUR NAMESPACE (PARTIAL)
namespace KJUR {
namespace crypto {
type CurveName = 'secp128r1' | 'secp160k1' | 'secp160r1' | 'secp192k1' | 'secp192r1' | 'secp224r1' | 'secp256k1' | 'secp256r1' | 'secp384r1' | 'secp521r1';
class DSA {
public p: BigInteger | null;
public q: BigInteger | null;
public g: BigInteger | null;
public y: BigInteger | null;
public x: BigInteger | null;
public type: 'DSA';
public isPrivate: boolean;
public isPublic: boolean;
public setPrivate(p: BigInteger, q: BigInteger, g: BigInteger, y: BigInteger | null, x: BigInteger): void;
public setPrivateHex(hP: HexString, hQ: HexString, hG: HexString, hY: HexString | null, hX: HexString): void;
public setPublic(p: BigInteger, q: BigInteger, g: BigInteger, y: BigInteger): void;
public setPublicHex(hP: HexString, hQ: HexString, hG: HexString, hY: HexString): void;
public signWithMessageHash(sHashHex: HexString): HexString;
public verifyWithMessageHash(sHashHex: HexString, hSigVal: HexString): boolean;
public parseASN1Signature(hSigVal: HexString): [BigInteger, BigInteger];
public readPKCS5PrvKeyHex(h: HexString): void;
public readPKCS8PrvKeyHex(h: HexString): void;
public readPKCS8PubKeyHex(h: HexString): void;
public readCertPubKeyHex(h: HexString, nthPKI: number): void;
}
class ECDSA {
constructor(params?: {
curve?: CurveName;
prv?: HexString;
pub?: HexString;
});
public p: BigInteger | null;
public q: BigInteger | null;
public g: BigInteger | null;
public y: BigInteger | null;
public x: BigInteger | null;
public type: 'EC';
public isPrivate: boolean;
public isPublic: boolean;
public getBigRandom(limit: BigInteger): BigInteger;
public setNamedCurve(curveName: CurveName): void;
public setPrivateKeyHex(prvKeyHex: HexString): void;
public setPublicKeyHex(pubKeyHex: HexString): void;
public getPublicKeyXYHex(): Record<'x' | 'y', HexString>;
public getShortNISTPCurveName(): 'P-256' | 'P-384' | null;
public generateKeyPairHex(): Record<'ecprvhex' | 'ecpubhex', HexString>;
public signWithMessageHash(hashHex: HexString): HexString;
public signHex(hashHex: HexString, privHex: HexString): HexString;
public verifyWithMessageHash(sHashHex: HexString, hSigVal: HexString): boolean;
public parseASN1Signature(hSigVal: HexString): [BigInteger, BigInteger];
public readPKCS5PrvKeyHex(h: HexString): void;
public readPKCS8PrvKeyHex(h: HexString): void;
public readPKCS8PubKeyHex(h: HexString): void;
public readCertPubKeyHex(h: HexString, nthPKI: number): void;
public static parseSigHex(sigHex: HexString): Record<'r' | 's', BigInteger>;
public static parseSigHexInHexRS(sigHex: HexString): Record<'r' | 's', ASN1V>;
public static asn1SigToConcatSig(asn1Sig: HexString): HexString;
public static concatSigToASN1Sig(concatSig: HexString): ASN1TLV;
public static hexRSSigToASN1Sig(hR: HexString, hS: HexString): ASN1TLV;
public static biRSSigToASN1Sig(biR: BigInteger, biS: BigInteger): ASN1TLV;
public static getName(s: CurveName | HexString): 'secp256r1' | 'secp256k1' | 'secp384r1' | null;
}
class Signature {
constructor(params?: ({
alg: string;
prov?: string;
} | {}) & ({
psssaltlen: number;
} | {}) & ({
prvkeypem: PEM;
prvkeypas?: never;
} | {}));
private _setAlgNames(): void;
private _zeroPaddingOfSignature(hex: HexString, bitLength: number): HexString;
public setAlgAndProvider(alg: string, prov: string): void;
public init(key: GetKeyParam, pass?: string): void;
public updateString(str: string): void;
public updateHex(hex: HexString): void;
public sign(): HexString;
public signString(str: string): HexString;
public signHex(hex: HexString): HexString;
public verify(hSigVal: string): boolean | 0;
}
}
}
//// RSAKEY TYPES
class RSAKey {
public n: BigInteger | null;
public e: number;
public d: BigInteger | null;
public p: BigInteger | null;
public q: BigInteger | null;
public dmp1: BigInteger | null;
public dmq1: BigInteger | null;
public coeff: BigInteger | null;
public type: 'RSA';
public isPrivate?: boolean;
public isPublic?: boolean;
//// RSA PUBLIC
protected doPublic(x: BigInteger): BigInteger;
public setPublic(N: BigInteger, E: number): void;
public setPublic(N: HexString, E: HexString): void;
public encrypt(text: string): HexString | null;
public encryptOAEP(text: string, hash?: string, hashLen?: number): HexString | null;
public encryptOAEP(text: string, hash?: (s: string) => string, hashLen?: number): HexString | null;
//// RSA PRIVATE
protected doPrivate(x: BigInteger): BigInteger;
public setPrivate(N: BigInteger, E: number, D: BigInteger): void;
public setPrivate(N: HexString, E: HexString, D: HexString): void;
public setPrivateEx(N: HexString, E: HexString, D?: HexString | null, P?: HexString | null, Q?: HexString | null, DP?: HexString | null, DQ?: HexString | null, C?: HexString | null): void;
public generate(B: number, E: HexString): void;
public decrypt(ctext: HexString): string;
public decryptOAEP(ctext: HexString, hash?: string, hashLen?: number): string | null;
public encryptOAEP(ctext: HexString, hash?: (s: string) => string, hashLen?: number): string | null;
//// RSA PEM
public getPosArrayOfChildrenFromHex(hPrivateKey: PEM): Idx<ASN1ObjectString>[];
public getHexValueArrayOfChildrenFromHex(hPrivateKey: PEM): Idx<ASN1ObjectString>[];
public readPrivateKeyFromPEMString(keyPEM: PEM): void;
public readPKCS5PrvKeyHex(h: HexString): void;
public readPKCS8PrvKeyHex(h: HexString): void;
public readPKCS5PubKeyHex(h: HexString): void;
public readPKCS8PubKeyHex(h: HexString): void;
public readCertPubKeyHex(h: HexString, nthPKI: Nth): void;
//// RSA SIGN
public sign(s: string, hashAlg: string): HexString;
public signWithMessageHash(sHashHex: HexString, hashAlg: string): HexString;
public signPSS(s: string, hashAlg: string, sLen: number): HexString;
public signWithMessageHashPSS(hHash: HexString, hashAlg: string, sLen: number): HexString;
public verify(sMsg: string, hSig: HexString): boolean | 0;
public verifyWithMessageHash(sHashHex: HexString, hSig: HexString): boolean | 0;
public verifyPSS(sMsg: string, hSig: HexString, hashAlg: string, sLen: number): boolean;
public verifyWithMessageHashPSS(hHash: HexString, hSig: HexString, hashAlg: string, sLen: number): boolean;
public static SALT_LEN_HLEN: -1;
public static SALT_LEN_MAX: -2;
public static SALT_LEN_RECOVER: -2;
}
/// RNG TYPES
class SecureRandom {
public nextBytes(ba: Mutable<ByteNumber[]>): void;
}
//// X509 TYPES
type ExtInfo = {
critical: boolean;
oid: OID;
vidx: Idx<ASN1V>;
};
type ExtAIAInfo = Record<'ocsp' | 'caissuer', string>;
type ExtCertificatePolicy = {
id: OIDName;
} & Partial<{
cps: string;
} | {
unotice: string;
}>;
class X509 {
public hex: HexString | null;
public version: number;
public foffset: number;
public aExtInfo: null;
public getVersion(): number;
public getSerialNumberHex(): ASN1V;
public getSignatureAlgorithmField(): OIDName;
public getIssuerHex(): ASN1TLV;
public getIssuerString(): HexString;
public getSubjectHex(): ASN1TLV;
public getSubjectString(): HexString;
public getNotBefore(): TimeValue;
public getNotAfter(): TimeValue;
public getPublicKeyHex(): ASN1TLV;
public getPublicKeyIdx(): Idx<Mutable<Nth[]>>;
public getPublicKeyContentIdx(): Idx<Mutable<Nth[]>>;
public getPublicKey(): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
public getSignatureAlgorithmName(): OIDName;
public getSignatureValueHex(): ASN1V;
public verifySignature(pubKey: GetKeyParam): boolean | 0;
public parseExt(): void;
public getExtInfo(oidOrName: OID | string): ExtInfo | undefined;
public getExtBasicConstraints(): ExtInfo | {} | {
cA: true;
pathLen?: number;
};
public getExtKeyUsageBin(): BinString;
public getExtKeyUsageString(): string;
public getExtSubjectKeyIdentifier(): ASN1V | undefined;
public getExtAuthorityKeyIdentifier(): {
kid: ASN1V;
} | undefined;
public getExtExtKeyUsageName(): OIDName[] | undefined;
public getExtSubjectAltName(): Deprecated<string[]>;
public getExtSubjectAltName2(): ['MAIL' | 'DNS' | 'DN' | 'URI' | 'IP', string][] | undefined;
public getExtCRLDistributionPointsURI(): string[] | undefined;
public getExtAIAInfo(): ExtAIAInfo | undefined;
public getExtCertificatePolicies(): ExtCertificatePolicy[] | undefined;
public readCertPEM(sCertPEM: PEM): void;
public readCertHex(sCertHex: HexString): void;
public getInfo(): string;
public static hex2dn(hex: HexString, idx?: Idx<HexString>): string;
public static hex2rdn(hex: HexString, idx?: Idx<HexString>): string;
public static hex2attrTypeValue(hex: HexString, idx?: Idx<HexString>): string;
public static getPublicKeyFromCertPEM(sCertPEM: PEM): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
public static getPublicKeyInfoPropOfCertPEM(sCertPEM: PEM): {
algparam: ASN1V | null;
leyhex: ASN1V;
algoid: ASN1V;
};
}
}

View File

@@ -79,6 +79,7 @@ export async function masterMain() {
require('../daemons/server-stats').default(); require('../daemons/server-stats').default();
require('../daemons/notes-stats').default(); require('../daemons/notes-stats').default();
require('../daemons/queue-stats').default(); require('../daemons/queue-stats').default();
require('../daemons/janitor').default();
} }
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true); bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);

View File

@@ -124,7 +124,7 @@ export default Vue.extend({
this.connection = this.$root.stream.useSharedConnection('serverStats'); this.connection = this.$root.stream.useSharedConnection('serverStats');
this.updateStats(); this.updateStats();
this.clock = setInterval(this.updateStats, 1000); this.clock = setInterval(this.updateStats, 3000);
this.$root.getMeta().then(meta => { this.$root.getMeta().then(meta => {
this.meta = meta; this.meta = meta;

View File

@@ -0,0 +1,61 @@
<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

@@ -22,6 +22,7 @@
<li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>{{ $t('instance') }}</li> <li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>{{ $t('instance') }}</li>
<li @click="nav('queue')" :class="{ active: page == 'queue' }"><fa :icon="faTasks" fixed-width/>{{ $t('queue') }}</li> <li @click="nav('queue')" :class="{ active: page == 'queue' }"><fa :icon="faTasks" fixed-width/>{{ $t('queue') }}</li>
<li @click="nav('logs')" :class="{ active: page == 'logs' }"><fa :icon="faStream" fixed-width/>{{ $t('logs') }}</li> <li @click="nav('logs')" :class="{ active: page == 'logs' }"><fa :icon="faStream" fixed-width/>{{ $t('logs') }}</li>
<li @click="nav('db')" :class="{ active: page == 'db' }"><fa :icon="faDatabase" fixed-width/>{{ $t('db') }}</li>
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li> <li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li> <li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
<li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li> <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li>
@@ -43,6 +44,7 @@
<div v-if="page == 'instance'"><x-instance/></div> <div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'queue'"><x-queue/></div> <div v-if="page == 'queue'"><x-queue/></div>
<div v-if="page == 'logs'"><x-logs/></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 == 'moderators'"><x-moderators/></div>
<div v-if="page == 'users'"><x-users/></div> <div v-if="page == 'users'"><x-users/></div>
<div v-if="page == 'emoji'"><x-emoji/></div> <div v-if="page == 'emoji'"><x-emoji/></div>
@@ -59,19 +61,20 @@
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../i18n'; import i18n from '../../i18n';
import { version } from '../../config'; import { version } from '../../config';
import XDashboard from "./dashboard.vue"; import XDashboard from './dashboard.vue';
import XInstance from "./instance.vue"; import XInstance from './instance.vue';
import XQueue from "./queue.vue"; import XQueue from './queue.vue';
import XLogs from "./logs.vue"; import XLogs from './logs.vue';
import XModerators from "./moderators.vue"; import XDb from './db.vue';
import XEmoji from "./emoji.vue"; import XModerators from './moderators.vue';
import XAnnouncements from "./announcements.vue"; import XEmoji from './emoji.vue';
import XUsers from "./users.vue"; import XAnnouncements from './announcements.vue';
import XDrive from "./drive.vue"; import XUsers from './users.vue';
import XAbuse from "./abuse.vue"; import XDrive from './drive.vue';
import XFederation from "./federation.vue"; import XAbuse from './abuse.vue';
import XFederation from './federation.vue';
import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks, faStream } from '@fortawesome/free-solid-svg-icons'; import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks, faStream, faDatabase } from '@fortawesome/free-solid-svg-icons';
import { faGrin } from '@fortawesome/free-regular-svg-icons'; import { faGrin } from '@fortawesome/free-regular-svg-icons';
// Detect the user agent // Detect the user agent
@@ -85,6 +88,7 @@ export default Vue.extend({
XInstance, XInstance,
XQueue, XQueue,
XLogs, XLogs,
XDb,
XModerators, XModerators,
XEmoji, XEmoji,
XAnnouncements, XAnnouncements,
@@ -108,7 +112,8 @@ export default Vue.extend({
faGlobe, faGlobe,
faExclamationCircle, faExclamationCircle,
faTasks, faTasks,
faStream faStream,
faDatabase,
}; };
}, },
methods: { methods: {

View File

@@ -129,6 +129,7 @@
<ui-input v-model="smtpPass" type="password" :with-password-toggle="true" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-pass') }}</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-horizon-group>
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<template #desc>{{ $t('smtp-secure-info') }}</template></ui-switch> <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> </template>
</section> </section>
<section> <section>
@@ -424,6 +425,24 @@ export default Vue.extend({
}); });
}, },
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() { updateMeta() {
this.$root.api('admin/update-meta', { this.$root.api('admin/update-meta', {
maintainerName: this.maintainerName, maintainerName: this.maintainerName,

View File

@@ -41,7 +41,6 @@
if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev'; if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth'; if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin'; if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin';
if (`${url.pathname}/`.startsWith('/test/')) app = 'test';
//#endregion //#endregion
// Script version // Script version
@@ -85,7 +84,14 @@
// Detect the user agent // Detect the user agent
const ua = navigator.userAgent.toLowerCase(); const ua = navigator.userAgent.toLowerCase();
const isMobile = /mobile|iphone|ipad|android/.test(ua); let isMobile = /mobile|iphone|ipad|android/.test(ua) || window.innerWidth < 576;
if (settings && settings.device.appTypeForce) {
if (settings.device.appTypeForce === 'mobile') {
isMobile = true;
} else if (settings.device.appTypeForce === 'desktop') {
isMobile = false;
}
}
// Get the <head> element // Get the <head> element
const head = document.getElementsByTagName('head')[0]; const head = document.getElementsByTagName('head')[0];

View File

@@ -60,9 +60,9 @@ export default function <T extends object>(data: {
save() { save() {
if (this.platform == 'deck') { if (this.platform == 'deck') {
this.$store.commit('device/updateDeckColumn', this.column); this.$store.commit('updateDeckColumn', this.column);
} else { } else {
this.$store.commit('device/updateWidget', this.widget); this.$store.commit('updateWidget', this.widget);
} }
} }
} }

View File

@@ -0,0 +1,5 @@
export function hexifyAB(buffer) {
return Array.from(new Uint8Array(buffer))
.map(item => item.toString(16).padStart(2, 0))
.join('');
}

View File

@@ -83,9 +83,19 @@ export default (opts: Opts = {}) => ({
if (this.appearNote.text) { if (this.appearNote.text) {
const ast = parse(this.appearNote.text); const ast = parse(this.appearNote.text);
// TODO: 再帰的にURL要素がないか調べる // TODO: 再帰的にURL要素がないか調べる
return unique(ast const urls = unique(ast
.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent)) .filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent))
.map(t => t.node.props.url)); .map(t => t.node.props.url));
// unique without hash
// [ http://a/#1, http://a/#2, http://b/#3 ] => [ http://a/#1, http://b/#3 ]
const removeHash = x => x.replace(/#[^#]*$/, '');
return urls.reduce((array, url) => {
const removed = removeHash(url);
if (!array.map(x => removeHash(x)).includes(removed)) array.push(url);
return array;
}, []);
} else { } else {
return null; return null;
} }

View File

@@ -5,6 +5,7 @@ export default (opts) => ({
return { return {
items: [], items: [],
queue: [], queue: [],
offset: 0,
fetching: true, fetching: true,
moreFetching: false, moreFetching: false,
inited: false, inited: false,
@@ -80,6 +81,7 @@ export default (opts) => ({
this.items = x; this.items = x;
this.more = false; this.more = false;
} }
this.offset = x.length;
this.inited = true; this.inited = true;
this.fetching = false; this.fetching = false;
if (opts.onInited) opts.onInited(this); if (opts.onInited) opts.onInited(this);
@@ -96,7 +98,11 @@ export default (opts) => ({
if (params && params.then) params = await params; if (params && params.then) params = await params;
await this.$root.api(this.pagination.endpoint, { await this.$root.api(this.pagination.endpoint, {
limit: (this.pagination.limit || 10) + 1, limit: (this.pagination.limit || 10) + 1,
untilId: this.items[this.items.length - 1].id, ...(this.pagination.endpoint === 'notes/search' ? {
offset: this.offset,
} : {
untilId: this.items[this.items.length - 1].id,
}),
...params ...params
}).then(x => { }).then(x => {
if (x.length == (this.pagination.limit || 10) + 1) { if (x.length == (this.pagination.limit || 10) + 1) {
@@ -107,6 +113,7 @@ export default (opts) => ({
this.items = this.items.concat(x); this.items = this.items.concat(x);
this.more = false; this.more = false;
} }
this.offset += x.length;
this.moreFetching = false; this.moreFetching = false;
}, e => { }, e => {
this.moreFetching = false; this.moreFetching = false;

View File

@@ -8,6 +8,7 @@ import { host, url } from '../../config';
import i18n from '../../i18n'; import i18n from '../../i18n';
import { erase, unique } from '../../../../prelude/array'; import { erase, unique } from '../../../../prelude/array';
import extractMentions from '../../../../misc/extract-mentions'; import extractMentions from '../../../../misc/extract-mentions';
import { formatTimeString } from '../../../../misc/format-time-string';
export default (opts) => ({ export default (opts) => ({
i18n: i18n(), i18n: i18n(),
@@ -151,9 +152,16 @@ export default (opts) => ({
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ // 公開以外へのリプライ時は元の公開範囲を引き継ぐ
if (this.reply && ['home', 'followers', 'specified'].includes(this.reply.visibility)) { if (this.reply && ['home', 'followers', 'specified'].includes(this.reply.visibility)) {
this.visibility = this.reply.visibility; this.visibility = this.reply.visibility;
if (this.reply.visibility === 'specified') {
this.$root.api('users/show', {
userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$store.state.i.id && uid !== this.reply.userId)
}).then(users => {
this.visibleUsers.push(...users);
});
}
} }
if (this.reply) { if (this.reply && this.reply.userId !== this.$store.state.i.id) {
this.$root.api('users/show', { userId: this.reply.userId }).then(user => { this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
this.visibleUsers.push(user); this.visibleUsers.push(user);
}); });
@@ -237,8 +245,8 @@ export default (opts) => ({
for (const x of Array.from((this.$refs.file as any).files)) this.upload(x); for (const x of Array.from((this.$refs.file as any).files)) this.upload(x);
}, },
upload(file) { upload(file: File, name?: string) {
(this.$refs.uploader as any).upload(file); (this.$refs.uploader as any).upload(file, this.$store.state.settings.uploadFolder, name);
}, },
onChangeUploadings(uploads) { onChangeUploadings(uploads) {
@@ -327,10 +335,23 @@ export default (opts) => ({
if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey) && this.canPost) this.post(); if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey) && this.canPost) this.post();
}, },
async onPaste(e) { async onPaste(e: ClipboardEvent) {
for (const item of Array.from(e.clipboardData.items)) { for (const { item, i } of Array.from(e.clipboardData.items).map((item, i) => ({item, i}))) {
if (item.kind == 'file') { if (item.kind == 'file') {
this.upload(item.getAsFile()); const file = item.getAsFile();
const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : '';
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.settings.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
const name = this.$store.state.settings.pasteDialog
? await this.$root.dialog({
title: this.$t('@.post-form.enter-file-name'),
input: {
default: formatted
},
allowEmpty: false
}).then(({ canceled, result }) => canceled ? false : result)
: formatted;
if (name) this.upload(file, name);
} }
} }

View File

@@ -72,6 +72,9 @@ export default Vue.extend({
columnWidth: '80%' columnWidth: '80%'
} }
}, },
dataLabels: {
enabled: false
},
grid: { grid: {
clipMarkers: false, clipMarkers: false,
padding: { padding: {

View File

@@ -16,7 +16,7 @@
</ol> </ol>
<ol class="emojis" ref="suggests" v-if="emojis.length > 0"> <ol class="emojis" ref="suggests" v-if="emojis.length > 0">
<li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1"> <li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1">
<span class="emoji" v-if="emoji.isCustomEmoji"><img :src="emoji.url" :alt="emoji.emoji"/></span> <span class="emoji" v-if="emoji.isCustomEmoji"><img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else-if="!useOsDefaultEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span> <span class="emoji" v-else-if="!useOsDefaultEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else>{{ emoji.emoji }}</span> <span class="emoji" v-else>{{ emoji.emoji }}</span>
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span> <span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
@@ -31,6 +31,7 @@ import Vue from 'vue';
import * as emojilib from 'emojilib'; import * as emojilib from 'emojilib';
import contains from '../../../common/scripts/contains'; import contains from '../../../common/scripts/contains';
import { twemojiBase } from '../../../../../misc/twemoji-base'; import { twemojiBase } from '../../../../../misc/twemoji-base';
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
type EmojiDef = { type EmojiDef = {
emoji: string; emoji: string;
@@ -78,6 +79,7 @@ export default Vue.extend({
data() { data() {
return { return {
getStaticImageUrl,
fetching: true, fetching: true,
users: [], users: [],
hashtags: [], hashtags: [],

View File

@@ -33,7 +33,7 @@
</template> </template>
</ui-select> </ui-select>
<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash && (showOkButton || showCancelButton)"> <ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash && (showOkButton || showCancelButton)">
<ui-button @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button> <ui-button @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user" :disabled="!canOk">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button>
<ui-button @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('@.cancel') }}</ui-button> <ui-button @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('@.cancel') }}</ui-button>
</ui-horizon-group> </ui-horizon-group>
</template> </template>
@@ -99,11 +99,26 @@ export default Vue.extend({
inputValue: this.input && this.input.default ? this.input.default : null, inputValue: this.input && this.input.default ? this.input.default : null,
userInputValue: null, userInputValue: null,
selectedValue: this.select ? this.select.items ? this.select.items[0].value : this.select.groupedItems[0].items[0].value : null, selectedValue: this.select ? this.select.items ? this.select.items[0].value : this.select.groupedItems[0].items[0].value : null,
canOk: true,
faTimesCircle, faQuestionCircle faTimesCircle, faQuestionCircle
}; };
}, },
watch: {
userInputValue() {
if (this.user) {
this.$root.api('users/show', parseAcct(this.userInputValue)).then(u => {
this.canOk = u != null;
}).catch(() => {
this.canOk = false;
});
}
}
},
mounted() { mounted() {
if (this.user) this.canOk = false;
this.$nextTick(() => { this.$nextTick(() => {
(this.$refs.bg as any).style.pointerEvents = 'auto'; (this.$refs.bg as any).style.pointerEvents = 'auto';
anime({ anime({
@@ -131,6 +146,7 @@ export default Vue.extend({
methods: { methods: {
async ok() { async ok() {
if (!this.canOk) return;
if (!this.showOkButton) return; if (!this.showOkButton) return;
if (this.user) { if (this.user) {

View File

@@ -55,6 +55,20 @@ export default Vue.extend({
} }
}, },
watch: {
customEmojis() {
if (this.name) {
const customEmoji = this.customEmojis.find(x => x.name == this.name);
if (customEmoji) {
this.customEmoji = customEmoji;
this.url = this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(customEmoji.url)
: customEmoji.url;
}
}
},
},
created() { created() {
if (this.name) { if (this.name) {
const customEmoji = this.customEmojis.find(x => x.name == this.name); const customEmoji = this.customEmojis.find(x => x.name == this.name);
@@ -80,7 +94,7 @@ export default Vue.extend({
this.url = `${twemojiBase}/2/svg/${codes.join('-')}.svg`; this.url = `${twemojiBase}/2/svg/${codes.join('-')}.svg`;
} }
} },
}); });
</script> </script>

View File

@@ -92,6 +92,14 @@ export default Vue.extend({
try { try {
if (this.isFollowing) { if (this.isFollowing) {
const { canceled } = await this.$root.dialog({
type: 'warning',
text: this.$t('@.unfollow-confirm', { name: this.user.name || this.user.username }),
showCancelButton: true
});
if (canceled) return;
await this.$root.api('following/delete', { await this.$root.api('following/delete', {
userId: this.user.id userId: this.user.id
}); });

View File

@@ -5,17 +5,17 @@
<div style="overflow: hidden; line-height: 28px;"> <div style="overflow: hidden; line-height: 28px;">
<p class="turn" v-if="!iAmPlayer && !game.isEnded"> <p class="turn" v-if="!iAmPlayer && !game.isEnded">
<mfm :key="'turn:' + $options.filters.userName(turnUser)" :text="$t('@.reversi.turn-of', { name: $options.filters.userName(turnUser) })" :should-break="false" :plain-text="true" :custom-emojis="turnUser.emojis"/> <mfm :key="'turn:' + $options.filters.userName(turnUser)" :text="$t('@.reversi.turn-of', { name: $options.filters.userName(turnUser) })" :plain="true" :custom-emojis="turnUser.emojis"/>
<mk-ellipsis/> <mk-ellipsis/>
</p> </p>
<p class="turn" v-if="logPos != logs.length"> <p class="turn" v-if="logPos != logs.length">
<mfm :key="'past-turn-of:' + $options.filters.userName(turnUser)" :text="$t('@.reversi.past-turn-of', { name: $options.filters.userName(turnUser) })" :should-break="false" :plain-text="true" :custom-emojis="turnUser.emojis"/> <mfm :key="'past-turn-of:' + $options.filters.userName(turnUser)" :text="$t('@.reversi.past-turn-of', { name: $options.filters.userName(turnUser) })" :plain="true" :custom-emojis="turnUser.emojis"/>
</p> </p>
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">{{ $t('@.reversi.opponent-turn') }}<mk-ellipsis/></p> <p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">{{ $t('@.reversi.opponent-turn') }}<mk-ellipsis/></p>
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">{{ $t('@.reversi.my-turn') }}</p> <p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">{{ $t('@.reversi.my-turn') }}</p>
<p class="result" v-if="game.isEnded && logPos == logs.length"> <p class="result" v-if="game.isEnded && logPos == logs.length">
<template v-if="game.winner"> <template v-if="game.winner">
<mfm :key="'won'" :text="$t('@.reversi.won', { name: $options.filters.userName(game.winner) })" :should-break="false" :plain-text="true" :custom-emojis="game.winner.emojis"/> <mfm :key="'won'" :text="$t('@.reversi.won', { name: $options.filters.userName(game.winner) })" :plain="true" :custom-emojis="game.winner.emojis"/>
<span v-if="game.surrendered != null"> ({{ $t('surrendered') }})</span> <span v-if="game.surrendered != null"> ({{ $t('surrendered') }})</span>
</template> </template>
<template v-else>{{ $t('@.reversi.drawn') }}</template> <template v-else>{{ $t('@.reversi.drawn') }}</template>

View File

@@ -41,7 +41,6 @@ export default Vue.extend({
padding 10px padding 10px
width 100% width 100%
height 40px height 40px
font-family sans-serif
font-size 16px font-size 16px
color var(--googleSearchFg) color var(--googleSearchFg)
background var(--googleSearchBg) background var(--googleSearchBg)

View File

@@ -30,6 +30,7 @@
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import * as autosize from 'autosize'; import * as autosize from 'autosize';
import { formatTimeString } from '../../../../../misc/format-time-string';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.form.vue'), i18n: i18n('common/views/components/messaging-room.form.vue'),
@@ -84,13 +85,26 @@ export default Vue.extend({
} }
}, },
methods: { methods: {
onPaste(e) { async onPaste(e: ClipboardEvent) {
const data = e.clipboardData; const data = e.clipboardData;
const items = data.items; const items = data.items;
if (items.length == 1) { if (items.length == 1) {
if (items[0].kind == 'file') { if (items[0].kind == 'file') {
this.upload(items[0].getAsFile()); const file = items[0].getAsFile();
const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : '';
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.settings.pastedFileName).replace(/{{number}}/g, '1')}${ext}`;
const name = this.$store.state.settings.pasteDialog
? await this.$root.dialog({
title: this.$t('@.post-form.enter-file-name'),
input: {
default: formatted
},
allowEmpty: false
}).then(({ canceled, result }) => canceled ? false : result)
: formatted;
if (name) this.upload(file, name);
} }
} else { } else {
if (items[0].kind == 'file') { if (items[0].kind == 'file') {
@@ -157,8 +171,8 @@ export default Vue.extend({
this.upload((this.$refs.file as any).files[0]); this.upload((this.$refs.file as any).files[0]);
}, },
upload(file) { upload(file: File, name?: string) {
(this.$refs.uploader as any).upload(file); (this.$refs.uploader as any).upload(file, this.$store.state.settings.uploadFolder, name);
}, },
onUploaded(file) { onUploaded(file) {

View File

@@ -22,11 +22,11 @@ export default Vue.component('misskey-flavored-markdown', {
type: String, type: String,
required: true required: true
}, },
shouldBreak: { plain: {
type: Boolean, type: Boolean,
default: true default: false
}, },
plainText: { nowrap: {
type: Boolean, type: Boolean,
default: false default: false
}, },
@@ -50,7 +50,7 @@ export default Vue.component('misskey-flavored-markdown', {
render(createElement) { render(createElement) {
if (this.text == null || this.text == '') return; if (this.text == null || this.text == '') return;
const ast = (this.plainText ? parsePlain : parse)(this.text); const ast = (this.plain ? parsePlain : parse)(this.text);
let bigCount = 0; let bigCount = 0;
let motionCount = 0; let motionCount = 0;
@@ -60,7 +60,7 @@ export default Vue.component('misskey-flavored-markdown', {
case 'text': { case 'text': {
const text = token.node.props.text.replace(/(\r\n|\n|\r)/g, '\n'); const text = token.node.props.text.replace(/(\r\n|\n|\r)/g, '\n');
if (this.shouldBreak) { if (!this.plain) {
const x = text.split('\n') const x = text.split('\n')
.map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]); .map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]);
x[x.length - 1].pop(); x[x.length - 1].pop();
@@ -270,7 +270,7 @@ export default Vue.component('misskey-flavored-markdown', {
}, },
props: { props: {
customEmojis: this.customEmojis || customEmojis, customEmojis: this.customEmojis || customEmojis,
normal: this.plainText normal: this.plain
} }
})]; })];
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<mfm-core v-bind="$attrs" class="havbbuyv" v-once/> <mfm-core v-bind="$attrs" class="havbbuyv" :class="{ nowrap: $attrs['nowrap'] }" v-once/>
</template> </template>
<script lang="ts"> <script lang="ts">
@@ -15,6 +15,11 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.havbbuyv .havbbuyv
white-space pre-wrap
&.nowrap
white-space pre
>>> .title >>> .title
display block display block
margin-bottom 4px margin-bottom 4px

View File

@@ -9,7 +9,6 @@ import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import { url } from '../../../config'; import { url } from '../../../config';
import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
import { concat, intersperse } from '../../../../../prelude/array';
import { faCopy, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; import { faCopy, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({ export default Vue.extend({
@@ -129,6 +128,13 @@ export default Vue.extend({
splash: true splash: true
}); });
this.destroyDom(); this.destroyDom();
}).catch(e => {
if (e.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
this.$root.dialog({
type: 'error',
text: this.$t('pin-limit-exceeded')
});
}
}); });
}, },

View File

@@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<ui-button class="kudkigyw" @click="click()">{{ script.interpolate(value.text) }}</ui-button> <ui-button class="kudkigyw" @click="click()" :primary="value.primary">{{ script.interpolate(value.text) }}</ui-button>
</div> </div>
</template> </template>
@@ -27,6 +27,19 @@ export default Vue.extend({
} else if (this.value.action === 'resetRandom') { } else if (this.value.action === 'resetRandom') {
this.script.aiScript.updateRandomSeed(Math.random()); this.script.aiScript.updateRandomSeed(Math.random());
this.script.eval(); this.script.eval();
} else if (this.value.action === 'pushEvent') {
this.$root.api('page-push', {
pageId: this.script.page.id,
event: this.value.event,
...(this.value.var ? {
var: this.script.vars[this.value.var]
} : {})
});
this.$root.dialog({
type: 'success',
text: this.script.interpolate(this.value.message)
});
} }
} }
} }
@@ -36,7 +49,7 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.kudkigyw .kudkigyw
display inline-block display inline-block
min-width 300px min-width 200px
max-width 450px max-width 450px
margin 8px 0 margin 8px 0
</style> </style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div v-if="page" class="iroscrza" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners, center: page.alignCenter }" :style="{ fontFamily: page.font }" :key="path"> <div class="iroscrza" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners, center: page.alignCenter, serif: page.font === 'serif' }">
<header> <header v-if="showTitle">
<div class="title">{{ page.title }}</div> <div class="title">{{ page.title }}</div>
</header> </header>
@@ -8,9 +8,13 @@
<x-block v-for="child in page.content" :value="child" @input="v => updateBlock(v)" :page="page" :script="script" :key="child.id" :h="2"/> <x-block v-for="child in page.content" :value="child" @input="v => updateBlock(v)" :page="page" :script="script" :key="child.id" :h="2"/>
</div> </div>
<footer> <footer v-if="showFooter">
<small>@{{ page.user.username }}</small> <small>@{{ page.user.username }}</small>
<router-link v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId" :to="`/i/pages/edit/${page.id}`">{{ $t('edit-this-page') }}</router-link> <template v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId">
<router-link :to="`/i/pages/edit/${page.id}`">{{ $t('edit-this-page') }}</router-link>
<a v-if="$store.state.i.pinnedPageId === page.id" @click="pin(false)">{{ $t('unpin-this-page') }}</a>
<a v-else @click="pin(true)">{{ $t('pin-this-page') }}</a>
</template>
<router-link :to="`./${page.name}/view-source`">{{ $t('view-source') }}</router-link> <router-link :to="`./${page.name}/view-source`">{{ $t('view-source') }}</router-link>
<div class="like"> <div class="like">
<button @click="unlike()" v-if="page.isLiked" :title="$t('unlike')"><fa :icon="faHeartS"/></button> <button @click="unlike()" v-if="page.isLiked" :title="$t('unlike')"><fa :icon="faHeartS"/></button>
@@ -25,7 +29,7 @@
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n'; import i18n from '../../../../i18n';
import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons'; import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons';
import { faHeart, faStickyNote } from '@fortawesome/free-regular-svg-icons'; import { faHeart } from '@fortawesome/free-regular-svg-icons';
import XBlock from './page.block.vue'; import XBlock from './page.block.vue';
import { ASEvaluator } from '../../../../../../misc/aiscript/evaluator'; import { ASEvaluator } from '../../../../../../misc/aiscript/evaluator';
import { collectPageVars } from '../../../scripts/collect-page-vars'; import { collectPageVars } from '../../../scripts/collect-page-vars';
@@ -35,8 +39,10 @@ class Script {
public aiScript: ASEvaluator; public aiScript: ASEvaluator;
private onError: any; private onError: any;
public vars: Record<string, any>; public vars: Record<string, any>;
public page: Record<string, any>;
constructor(aiScript, onError) { constructor(page, aiScript, onError) {
this.page = page;
this.aiScript = aiScript; this.aiScript = aiScript;
this.onError = onError; this.onError = onError;
this.eval(); this.eval();
@@ -67,64 +73,43 @@ export default Vue.extend({
}, },
props: { props: {
pageName: { page: {
type: String, type: Object,
required: true required: true
}, },
username: { showTitle: {
type: String, type: Boolean,
required: true required: false,
default: true
},
showFooter: {
type: Boolean,
required: false,
default: false
}, },
}, },
data() { data() {
return { return {
page: null,
script: null, script: null,
faHeartS, faHeart faHeartS, faHeart
}; };
}, },
computed: {
path(): string {
return this.username + '/' + this.pageName;
}
},
watch: {
path() {
this.fetch();
}
},
created() { created() {
this.fetch(); const pageVars = this.getPageVars();
this.script = new Script(this.page, new ASEvaluator(this.page.variables, pageVars, {
randomSeed: Math.random(),
user: this.page.user,
visitor: this.$store.state.i,
page: this.page,
url: url
}), e => {
console.dir(e);
});
}, },
methods: { methods: {
fetch() {
this.$root.api('pages/show', {
name: this.pageName,
username: this.username,
}).then(page => {
this.page = page;
this.$emit('init', {
title: this.page.title,
icon: faStickyNote
});
const pageVars = this.getPageVars();
this.script = new Script(new ASEvaluator(this.page.variables, pageVars, {
randomSeed: Math.random(),
user: page.user,
visitor: this.$store.state.i,
page: page,
url: url
}), e => {
console.dir(e);
});
});
},
getPageVars() { getPageVars() {
return collectPageVars(this.page.content); return collectPageVars(this.page.content);
}, },
@@ -145,6 +130,17 @@ export default Vue.extend({
this.page.isLiked = false; this.page.isLiked = false;
this.page.likedCount--; this.page.likedCount--;
}); });
},
pin(pin) {
this.$root.api('i/update', {
pinnedPageId: pin ? this.page.id : null,
}).then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
});
} }
} }
}); });
@@ -154,6 +150,10 @@ export default Vue.extend({
.iroscrza .iroscrza
overflow hidden overflow hidden
background var(--face) background var(--face)
&.serif
> div
font-family serif
&.center &.center
text-align center text-align center

View File

@@ -89,9 +89,7 @@ export default Vue.extend({
get() { get() {
const at = () => { const at = () => {
const [date] = moment(this.atDate).toISOString().split('T'); return moment(`${this.atDate} ${this.atTime}`).valueOf();
const [hour, minute] = this.atTime.split(':');
return moment(`${date}T${hour}:${minute}Z`).valueOf();
}; };
const after = () => { const after = () => {

View File

@@ -5,7 +5,7 @@
<div class="backdrop" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div> <div class="backdrop" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div>
<span> <span>
<template v-if="choice.isVoted"><fa icon="check"/></template> <template v-if="choice.isVoted"><fa icon="check"/></template>
<mfm :text="choice.text" :should-break="false" :plain-text="true" :custom-emojis="note.emojis"/> <mfm :text="choice.text" :plain="true" :custom-emojis="note.emojis"/>
<span class="votes" v-if="showResult">({{ $t('vote-count').replace('{}', choice.votes) }})</span> <span class="votes" v-if="showResult">({{ $t('vote-count').replace('{}', choice.votes) }})</span>
</span> </span>
</li> </li>

View File

@@ -15,9 +15,14 @@ export default Vue.extend({
}, },
data() { data() {
return { return {
customEmojis: (this.$root.getMetaSync() || { emojis: [] }).emojis || [] customEmojis: []
}; };
}, },
created() {
this.$root.getMeta().then(meta => {
if (meta && meta.emojis) this.customEmojis = meta.emojis;
});
},
computed: { computed: {
str(): any { str(): any {
switch (this.reaction) { switch (this.reaction) {

View File

@@ -1,11 +1,58 @@
<template> <template>
<div class="2fa"> <div class="2fa totp-section">
<p style="margin-top:0;">{{ $t('intro') }}<a :href="$t('url')" target="_blank">{{ $t('detail') }}</a></p> <p style="margin-top:0;">{{ $t('intro') }}<a :href="$t('url')" target="_blank">{{ $t('detail') }}</a></p>
<ui-info warn>{{ $t('caution') }}</ui-info> <ui-info warn>{{ $t('caution') }}</ui-info>
<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">{{ $t('register') }}</ui-button></p> <p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">{{ $t('register') }}</ui-button></p>
<template v-if="$store.state.i.twoFactorEnabled"> <template v-if="$store.state.i.twoFactorEnabled">
<h2 class="heading">{{ $t('totp-header') }}</h2>
<p>{{ $t('already-registered') }}</p> <p>{{ $t('already-registered') }}</p>
<ui-button @click="unregister">{{ $t('unregister') }}</ui-button> <ui-button @click="unregister">{{ $t('unregister') }}</ui-button>
<template v-if="supportsCredentials">
<hr class="totp-method-sep">
<h2 class="heading">{{ $t('security-key-header') }}</h2>
<p>{{ $t('security-key') }}</p>
<div class="key-list">
<div class="key" v-for="key in $store.state.i.securityKeysList">
<h3>
{{ key.name }}
</h3>
<div class="last-used">
{{ $t('last-used') }}
<mk-time :time="key.lastUsed"/>
</div>
<ui-button @click="unregisterKey(key)">
{{ $t('unregister') }}
</ui-button>
</div>
</div>
<ui-switch v-model="usePasswordLessLogin" @change="updatePasswordLessLogin" v-if="$store.state.i.securityKeysList.length > 0">
{{ $t('use-password-less-login') }}
</ui-switch>
<ui-info warn v-if="registration && registration.error">{{ $t('something-went-wrong') }} {{ registration.error }}</ui-info>
<ui-button v-if="!registration || registration.error" @click="addSecurityKey">{{ $t('register') }}</ui-button>
<ol v-if="registration && !registration.error">
<li v-if="registration.stage >= 0">
{{ $t('activate-key') }}
<fa icon="spinner" pulse fixed-width v-if="registration.saving && registration.stage == 0" />
</li>
<li v-if="registration.stage >= 1">
<ui-form :disabled="registration.stage != 1 || registration.saving">
<ui-input v-model="keyName" :max="30">
<span>{{ $t('security-key-name') }}</span>
</ui-input>
<ui-button @click="registerKey" :disabled="this.keyName.length == 0">
{{ $t('register-security-key') }}
</ui-button>
<fa icon="spinner" pulse fixed-width v-if="registration.saving && registration.stage == 1" />
</ui-form>
</li>
</ol>
</template>
</template> </template>
<div v-if="data && !$store.state.i.twoFactorEnabled"> <div v-if="data && !$store.state.i.twoFactorEnabled">
<ol> <ol>
@@ -24,12 +71,22 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../../i18n'; import i18n from '../../../../i18n';
import { hostname } from '../../../../config';
import { hexifyAB } from '../../../scripts/2fa';
function stringifyAB(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/settings.2fa.vue'), i18n: i18n('desktop/views/components/settings.2fa.vue'),
data() { data() {
return { return {
data: null, data: null,
supportsCredentials: !!navigator.credentials,
usePasswordLessLogin: this.$store.state.i.usePasswordLessLogin,
registration: null,
keyName: '',
token: null token: null
}; };
}, },
@@ -60,6 +117,9 @@ export default Vue.extend({
if (canceled) return; if (canceled) return;
this.$root.api('i/2fa/unregister', { this.$root.api('i/2fa/unregister', {
password: password password: password
}).then(() => {
this.usePasswordLessLogin = false;
this.updatePasswordLessLogin();
}).then(() => { }).then(() => {
this.$notify(this.$t('unregistered')); this.$notify(this.$t('unregistered'));
this.$store.state.i.twoFactorEnabled = false; this.$store.state.i.twoFactorEnabled = false;
@@ -76,7 +136,124 @@ export default Vue.extend({
}).catch(() => { }).catch(() => {
this.$notify(this.$t('failed')); this.$notify(this.$t('failed'));
}); });
},
registerKey() {
this.registration.saving = true;
this.$root.api('i/2fa/key-done', {
password: this.registration.password,
name: this.keyName,
challengeId: this.registration.challengeId,
// we convert each 16 bits to a string to serialise
clientDataJSON: stringifyAB(this.registration.credential.response.clientDataJSON),
attestationObject: hexifyAB(this.registration.credential.response.attestationObject)
}).then(key => {
this.registration = null;
key.lastUsed = new Date();
this.$notify(this.$t('success'));
})
},
unregisterKey(key) {
this.$root.dialog({
title: this.$t('enter-password'),
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
return this.$root.api('i/2fa/remove-key', {
password,
credentialId: key.id
}).then(() => {
this.usePasswordLessLogin = false;
this.updatePasswordLessLogin();
}).then(() => {
this.$notify(this.$t('key-unregistered'));
});
});
},
addSecurityKey() {
this.$root.dialog({
title: this.$t('enter-password'),
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
this.$root.api('i/2fa/register-key', {
password
}).then(registration => {
this.registration = {
password,
challengeId: registration.challengeId,
stage: 0,
publicKeyOptions: {
challenge: Buffer.from(
registration.challenge
.replace(/\-/g, "+")
.replace(/_/g, "/"),
'base64'
),
rp: {
id: hostname,
name: 'Misskey'
},
user: {
id: Uint8Array.from(this.$store.state.i.id, c => c.charCodeAt(0)),
name: this.$store.state.i.username,
displayName: this.$store.state.i.name,
},
pubKeyCredParams: [{alg: -7, type: 'public-key'}],
timeout: 60000,
attestation: 'direct'
},
saving: true
};
return navigator.credentials.create({
publicKey: this.registration.publicKeyOptions
});
}).then(credential => {
this.registration.credential = credential;
this.registration.saving = false;
this.registration.stage = 1;
}).catch(err => {
console.warn('Error while registering?', err);
this.registration.error = err.message;
this.registration.stage = -1;
});
});
},
updatePasswordLessLogin() {
this.$root.api('i/2fa/password-less', {
value: !!this.usePasswordLessLogin
});
} }
} }
}); });
</script> </script>
<style lang="stylus" scoped>
.totp-section
.totp-method-sep
margin 1.5em 0 1em
border none
border-top solid var(--lineWidth) var(--faceDivider)
h2.heading
margin 0
.key
padding 1em
margin 0.5em 0
background #161616
border-radius 6px
h3
margin-top 0
margin-bottom .3em
.last-used
margin-bottom .5em
</style>

View File

@@ -0,0 +1,36 @@
<template>
<ui-card>
<template #title><fa :icon="faMobileAlt"/> {{ $t('title') }}</template>
<section class="fit-top">
<p>{{ $t('intro') }}</p>
<ui-select v-model="appTypeForce" :placeholder="$t('intro')">
<option v-for="x in ['auto', 'desktop', 'mobile']" :value="x" :key="x">{{ $t(`choices.${x}`) }}</option>
</ui-select>
<ui-info warn>{{ $t('info') }}</ui-info>
</section>
</ui-card>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
import { faMobileAlt } from '@fortawesome/free-solid-svg-icons'
export default Vue.extend({
i18n: i18n('common/views/components/settings/app-type.vue'),
data() {
return {
faMobileAlt
};
},
computed: {
appTypeForce: {
get() { return this.$store.state.device.appTypeForce; },
set(value) { this.$store.commit('device/set', { key: 'appTypeForce', value }); }
},
},
});
</script>

View File

@@ -11,6 +11,12 @@
<header>{{ $t('stats') }}</header> <header>{{ $t('stats') }}</header>
<div ref="chart" style="margin-bottom: -16px; margin-left: -8px; color: #000;"></div> <div ref="chart" style="margin-bottom: -16px; margin-left: -8px; color: #000;"></div>
</section> </section>
<section>
<header>{{ $t('default-upload-folder') }}</header>
<ui-input v-model="uploadFolderName" readonly>{{ $t('default-upload-folder-name') }}</ui-input>
<ui-button @click="chooseUploadFolder()">{{ $t('change-default-upload-folder') }}</ui-button>
</section>
</ui-card> </ui-card>
</template> </template>
@@ -26,7 +32,8 @@ export default Vue.extend({
return { return {
fetching: true, fetching: true,
usage: null, usage: null,
capacity: null capacity: null,
uploadFolderName: null
}; };
}, },
@@ -40,10 +47,25 @@ export default Vue.extend({
l: 0.5 l: 0.5
}) })
}; };
} },
uploadFolder: {
get() { return this.$store.state.settings.uploadFolder; },
set(value) { this.$store.dispatch('settings/set', { key: 'uploadFolder', value }); }
},
}, },
mounted() { mounted() {
if (this.uploadFolder == null) {
this.uploadFolderName = this.$t('@._settings.root');
} else {
this.$root.api('drive/folders/show', {
folderId: this.uploadFolder
}).then(folder => {
this.uploadFolderName = folder.name;
});
}
this.$root.api('drive').then(info => { this.$root.api('drive').then(info => {
this.capacity = info.capacity; this.capacity = info.capacity;
this.usage = info.usage; this.usage = info.usage;
@@ -89,6 +111,9 @@ export default Vue.extend({
height: 150, height: 150,
zoom: { zoom: {
enabled: false enabled: false
},
toolbar: {
show: false
} }
}, },
plotOptions: { plotOptions: {
@@ -152,6 +177,13 @@ export default Vue.extend({
chart.render(); chart.render();
}); });
},
chooseUploadFolder() {
this.$chooseDriveFolder().then(folder => {
this.uploadFolder = folder ? folder.id : null;
this.uploadFolderName = folder ? folder.name : this.$t('@._settings.root');
})
} }
} }
}); });

View File

@@ -131,9 +131,28 @@
</section> </section>
</section> </section>
<section>
<header>{{ $t('@._settings.sync') }}</header>
<ui-input v-if="$root.isMobile" v-model="mobileHomeProfile" :datalist="Object.keys($store.state.settings.mobileHomeProfiles)">{{ $t('@._settings.home-profile') }}</ui-input>
<ui-input v-else v-model="homeProfile" :datalist="Object.keys($store.state.settings.homeProfiles)">{{ $t('@._settings.home-profile') }}</ui-input>
<ui-input v-model="deckProfile" :datalist="Object.keys($store.state.settings.deckProfiles)">{{ $t('@._settings.deck-profile') }}</ui-input>
</section>
<section> <section>
<header>{{ $t('@._settings.web-search-engine') }}</header> <header>{{ $t('@._settings.web-search-engine') }}</header>
<ui-input v-model="webSearchEngine">{{ $t('@._settings.web-search-engine') }}<template #desc>{{ $t('@._settings.web-search-engine-desc') }}</template></ui-input> <ui-input v-model="webSearchEngine">{{ $t('@._settings.web-search-engine') }}
<template #desc>{{ $t('@._settings.web-search-engine-desc') }}</template>
</ui-input>
</section>
<section v-if="!$root.isMobile">
<header>{{ $t('@._settings.paste') }}</header>
<ui-input v-model="pastedFileName">{{ $t('@._settings.pasted-file-name') }}
<template #desc>{{ $t('@._settings.pasted-file-name-desc') }}</template>
</ui-input>
<ui-switch v-model="pasteDialog">{{ $t('@._settings.paste-dialog') }}
<template #desc>{{ $t('@._settings.paste-dialog-desc') }}</template>
</ui-switch>
</section> </section>
</ui-card> </ui-card>
@@ -156,6 +175,7 @@
</ui-card> </ui-card>
<x-language/> <x-language/>
<x-app-type/>
</template> </template>
<template v-if="page == null || page == 'notification'"> <template v-if="page == null || page == 'notification'">
@@ -264,6 +284,7 @@ import XPassword from './password.vue';
import XProfile from './profile.vue'; import XProfile from './profile.vue';
import XApi from './api.vue'; import XApi from './api.vue';
import XLanguage from './language.vue'; import XLanguage from './language.vue';
import XAppType from './app-type.vue';
import XNotification from './notification.vue'; import XNotification from './notification.vue';
import { url, version } from '../../../../config'; import { url, version } from '../../../../config';
@@ -284,6 +305,7 @@ export default Vue.extend({
XProfile, XProfile,
XApi, XApi,
XLanguage, XLanguage,
XAppType,
XNotification, XNotification,
}, },
props: { props: {
@@ -402,6 +424,16 @@ export default Vue.extend({
set(value) { this.$store.dispatch('settings/set', { key: 'webSearchEngine', value }); } set(value) { this.$store.dispatch('settings/set', { key: 'webSearchEngine', value }); }
}, },
pastedFileName: {
get() { return this.$store.state.settings.pastedFileName; },
set(value) { this.$store.dispatch('settings/set', { key: 'pastedFileName', value }); }
},
pasteDialog: {
get() { return this.$store.state.settings.pasteDialog; },
set(value) { this.$store.dispatch('settings/set', { key: 'pasteDialog', value }); }
},
showReplyTarget: { showReplyTarget: {
get() { return this.$store.state.settings.showReplyTarget; }, get() { return this.$store.state.settings.showReplyTarget; },
set(value) { this.$store.dispatch('settings/set', { key: 'showReplyTarget', value }); } set(value) { this.$store.dispatch('settings/set', { key: 'showReplyTarget', value }); }
@@ -500,6 +532,21 @@ export default Vue.extend({
get() { return this.$store.state.device.mobileNotificationPosition; }, get() { return this.$store.state.device.mobileNotificationPosition; },
set(value) { this.$store.commit('device/set', { key: 'mobileNotificationPosition', value }); } set(value) { this.$store.commit('device/set', { key: 'mobileNotificationPosition', value }); }
}, },
homeProfile: {
get() { return this.$store.state.device.homeProfile; },
set(value) { this.$store.commit('device/set', { key: 'homeProfile', value }); }
},
mobileHomeProfile: {
get() { return this.$store.state.device.mobileHomeProfile; },
set(value) { this.$store.commit('device/set', { key: 'mobileHomeProfile', value }); }
},
deckProfile: {
get() { return this.$store.state.device.deckProfile; },
set(value) { this.$store.commit('device/set', { key: 'deckProfile', value }); }
},
}, },
created() { created() {
this.$root.getMeta().then(meta => { this.$root.getMeta().then(meta => {

View File

@@ -1,23 +1,44 @@
<template> <template>
<form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit"> <form class="mk-signin" :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div> <div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange"> <div class="normal-signin" v-if="!totpLogin">
<span>{{ $t('username') }}</span> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange">
<template #prefix>@</template> <span>{{ $t('username') }}</span>
<template #suffix>@{{ host }}</template> <template #prefix>@</template>
</ui-input> <template #suffix>@{{ host }}</template>
<ui-input v-model="password" type="password" :with-password-toggle="true" required> </ui-input>
<span>{{ $t('password') }}</span> <ui-input v-model="password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
<template #prefix><fa icon="lock"/></template> <span>{{ $t('password') }}</span>
</ui-input> <template #prefix><fa icon="lock"/></template>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required> </ui-input>
<span>{{ $t('@.2fa') }}</span> <ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
<template #prefix><fa icon="gavel"/></template> <p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`"><fa :icon="['fab', 'twitter']"/> {{ $t('signin-with-twitter') }}</a></p>
</ui-input> <p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`"><fa :icon="['fab', 'github']"/> {{ $t('signin-with-github') }}</a></p>
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button> <p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`"><fa :icon="['fab', 'discord']"/> {{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`"><fa :icon="['fab', 'twitter']"/> {{ $t('signin-with-twitter') }}</a></p> </div>
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`"><fa :icon="['fab', 'github']"/> {{ $t('signin-with-github') }}</a></p> <div class="2fa-signin" v-if="totpLogin" :class="{ securityKeys: user && user.securityKeys }">
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`"><fa :icon="['fab', 'discord']"/> {{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p> <div v-if="user && user.securityKeys" class="twofa-group tap-group">
<p>{{ $t('tap-key') }}</p>
<ui-button @click="queryKey" v-if="!queryingKey">
{{ $t('@.error.retry') }}
</ui-button>
</div>
<div class="or-hr" v-if="user && user.securityKeys">
<p class="or-msg">{{ $t('or') }}</p>
</div>
<div class="twofa-group totp-group">
<p style="margin-bottom:0;">{{ $t('enter-2fa-code') }}</p>
<ui-input v-model="password" type="password" :with-password-toggle="true" v-if="user && user.usePasswordLessLogin" required>
<span>{{ $t('password') }}</span>
<template #prefix><fa icon="lock"/></template>
</ui-input>
<ui-input v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
<span>{{ $t('@.2fa') }}</span>
<template #prefix><fa icon="gavel"/></template>
</ui-input>
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
</div>
</div>
</form> </form>
</template> </template>
@@ -26,6 +47,7 @@ import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import { apiUrl, host } from '../../../config'; import { apiUrl, host } from '../../../config';
import { toUnicode } from 'punycode'; import { toUnicode } from 'punycode';
import { hexifyAB } from '../../scripts/2fa';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/signin.vue'), i18n: i18n('common/views/components/signin.vue'),
@@ -47,7 +69,11 @@ export default Vue.extend({
token: '', token: '',
apiUrl, apiUrl,
host: toUnicode(host), host: toUnicode(host),
meta: null meta: null,
totpLogin: false,
credential: null,
challengeData: null,
queryingKey: false,
}; };
}, },
@@ -68,23 +94,93 @@ export default Vue.extend({
}); });
}, },
onSubmit() { queryKey() {
this.signing = true; this.queryingKey = true;
return navigator.credentials.get({
this.$root.api('signin', { publicKey: {
username: this.username, challenge: Buffer.from(
password: this.password, this.challengeData.challenge
token: this.user && this.user.twoFactorEnabled ? this.token : undefined .replace(/\-/g, '+')
.replace(/_/g, '/'),
'base64'
),
allowCredentials: this.challengeData.securityKeys.map(key => ({
id: Buffer.from(key.id, 'hex'),
type: 'public-key',
transports: ['usb', 'ble', 'nfc']
})),
timeout: 60 * 1000
}
}).catch(() => {
this.queryingKey = false;
return Promise.reject(null);
}).then(credential => {
this.queryingKey = false;
this.signing = true;
return this.$root.api('signin', {
username: this.username,
password: this.password,
signature: hexifyAB(credential.response.signature),
authenticatorData: hexifyAB(credential.response.authenticatorData),
clientDataJSON: hexifyAB(credential.response.clientDataJSON),
credentialId: credential.id,
challengeId: this.challengeData.challengeId
});
}).then(res => { }).then(res => {
localStorage.setItem('i', res.i); localStorage.setItem('i', res.i);
location.reload(); location.reload();
}).catch(() => { }).catch(err => {
if (err === null) return;
this.$root.dialog({ this.$root.dialog({
type: 'error', type: 'error',
text: this.$t('login-failed') text: this.$t('login-failed')
}); });
this.signing = false; this.signing = false;
}); });
},
onSubmit() {
this.signing = true;
if (!this.totpLogin && this.user && this.user.twoFactorEnabled) {
if (window.PublicKeyCredential && this.user.securityKeys) {
this.$root.api('signin', {
username: this.username,
password: this.password
}).then(res => {
this.totpLogin = true;
this.signing = false;
this.challengeData = res;
return this.queryKey();
}).catch(() => {
this.$root.dialog({
type: 'error',
text: this.$t('login-failed')
});
this.challengeData = null;
this.totpLogin = false;
this.signing = false;
});
} else {
this.totpLogin = true;
this.signing = false;
}
} else {
this.$root.api('signin', {
username: this.username,
password: this.password,
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
}).then(res => {
localStorage.setItem('i', res.i);
location.reload();
}).catch(() => {
this.$root.dialog({
type: 'error',
text: this.$t('login-failed')
});
this.signing = false;
});
}
} }
} }
}); });
@@ -94,6 +190,48 @@ export default Vue.extend({
.mk-signin .mk-signin
color #555 color #555
.or-hr,
.or-hr .or-msg,
.twofa-group,
.twofa-group p
color var(--text)
.tap-group > button
margin-bottom 1em
.securityKeys .or-hr
&
position relative
.or-msg
&:before
right 100%
margin-right 0.125em
&:after
left 100%
margin-left 0.125em
&:before, &:after
content ""
position absolute
top 50%
width 100%
height 2px
background #555
&
position relative
margin auto
left 0
right 0
top 0
bottom 0
font-size 1.5em
height 1.5em
width 3em
text-align center
&.signing &.signing
&, * &, *
cursor wait !important cursor wait !important

View File

@@ -46,7 +46,7 @@ export default Vue.extend({
}); });
}, },
upload(file: File, folder: any) { upload(file: File, folder: any, name?: string) {
if (folder && typeof folder == 'object') folder = folder.id; if (folder && typeof folder == 'object') folder = folder.id;
const id = Math.random(); const id = Math.random();
@@ -61,7 +61,7 @@ export default Vue.extend({
const ctx = { const ctx = {
id: id, id: id,
name: file.name || 'untitled', name: name || file.name || 'untitled',
progress: undefined, progress: undefined,
img: window.URL.createObjectURL(file) img: window.URL.createObjectURL(file)
}; };
@@ -75,6 +75,7 @@ export default Vue.extend({
data.append('file', file); data.append('file', file);
if (folder) data.append('folderId', folder); if (folder) data.append('folderId', folder);
if (name) data.append('name', name);
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open('POST', apiUrl + '/drive/files/create', true); xhr.open('POST', apiUrl + '/drive/files/create', true);

View File

@@ -30,7 +30,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import { url as local } from '../../../config'; import { url as local, lang } from '../../../config';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/url-preview.vue'), i18n: i18n('common/views/components/url-preview.vue'),
@@ -63,6 +63,7 @@ export default Vue.extend({
data() { data() {
const isSelf = this.url.startsWith(local); const isSelf = this.url.startsWith(local);
const hasRoute = const hasRoute =
(this.url.substr(local.length) === '/') ||
this.url.substr(local.length).startsWith('/@') || this.url.substr(local.length).startsWith('/@') ||
this.url.substr(local.length).startsWith('/notes/') || this.url.substr(local.length).startsWith('/notes/') ||
this.url.substr(local.length).startsWith('/pages/'); this.url.substr(local.length).startsWith('/pages/');
@@ -89,10 +90,10 @@ export default Vue.extend({
}, },
created() { created() {
const url = new URL(this.url); const requestUrl = new URL(this.url);
if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) { if (this.detail && requestUrl.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(requestUrl.pathname)) {
this.tweetUrl = url; this.tweetUrl = requestUrl;
const twttr = (window as any).twttr || {}; const twttr = (window as any).twttr || {};
const loadTweet = () => twttr.widgets.load(this.$refs.tweet); const loadTweet = () => twttr.widgets.load(this.$refs.tweet);
@@ -113,10 +114,15 @@ export default Vue.extend({
return; return;
} }
if (url.hostname === 'music.youtube.com') if (requestUrl.hostname === 'music.youtube.com') {
url.hostname = 'youtube.com'; requestUrl.hostname = 'youtube.com';
}
fetch(`/url?url=${encodeURIComponent(this.url)}`).then(res => { const requestLang = (lang || 'ja-JP').replace('ja-KS', 'ja-JP');
requestUrl.hash = '';
fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${requestLang}`).then(res => {
res.json().then(info => { res.json().then(info => {
if (info.url == null) return; if (info.url == null) return;
this.title = info.title; this.title = info.title;

View File

@@ -5,6 +5,9 @@
<span class="hostname">{{ hostname }}</span> <span class="hostname">{{ hostname }}</span>
<span class="port" v-if="port != ''">:{{ port }}</span> <span class="port" v-if="port != ''">:{{ port }}</span>
</template> </template>
<template v-if="pathname === '/' && self">
<span class="self">{{ hostname }}</span>
</template>
<span class="pathname" v-if="pathname != ''">{{ self ? pathname.substr(1) : pathname }}</span> <span class="pathname" v-if="pathname != ''">{{ self ? pathname.substr(1) : pathname }}</span>
<span class="query">{{ query }}</span> <span class="query">{{ query }}</span>
<span class="hash">{{ hash }}</span> <span class="hash">{{ hash }}</span>
@@ -22,6 +25,7 @@ export default Vue.extend({
data() { data() {
const isSelf = this.url.startsWith(local); const isSelf = this.url.startsWith(local);
const hasRoute = isSelf && ( const hasRoute = isSelf && (
(this.url.substr(local.length) === '/') ||
this.url.substr(local.length).startsWith('/@') || this.url.substr(local.length).startsWith('/@') ||
this.url.substr(local.length).startsWith('/notes/') || this.url.substr(local.length).startsWith('/notes/') ||
this.url.substr(local.length).startsWith('/pages/')); this.url.substr(local.length).startsWith('/pages/'));
@@ -54,19 +58,28 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.mk-url .mk-url
word-break break-all word-break break-all
> [data-icon] > [data-icon]
padding-left 2px padding-left 2px
font-size .9em font-size .9em
font-weight 400 font-weight 400
font-style normal font-style normal
> .self
font-weight bold
> .schema > .schema
opacity 0.5 opacity 0.5
> .hostname > .hostname
font-weight bold font-weight bold
> .pathname > .pathname
opacity 0.8 opacity 0.8
> .query > .query
opacity 0.5 opacity 0.5
> .hash > .hash
font-style italic font-style italic
</style> </style>

View File

@@ -16,7 +16,7 @@
<p class="username">@{{ user | acct }}</p> <p class="username">@{{ user | acct }}</p>
</div> </div>
<div class="description" v-if="user.description" :title="user.description"> <div class="description" v-if="user.description" :title="user.description">
<mfm :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis" :should-break="false" :plain-text="true"/> <mfm :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis" :plain="true" :nowrap="true"/>
</div> </div>
<mk-follow-button class="follow-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/> <mk-follow-button class="follow-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/>
</div> </div>

View File

@@ -1,5 +1,5 @@
<template> <template>
<mfm :text="user.name || user.username" :should-break="false" :plain-text="true" :custom-emojis="user.emojis"/> <mfm :text="user.name || user.username" :plain="true" :nowrap="true" :custom-emojis="user.emojis"/>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@@ -146,7 +146,8 @@ export default Vue.extend({
toggleActive() { toggleActive() {
if (!this.isStacked) return; if (!this.isStacked) return;
const vms = this.$store.state.device.deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id)); const deck = this.$store.state.device.deckProfile ? this.$store.state.settings.deckProfiles[this.$store.state.device.deckProfile] : this.$store.state.device.deck;
const vms = deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id));
if (this.active && countIf(vm => vm.$el.classList.contains('active'), vms) == 1) return; if (this.active && countIf(vm => vm.$el.classList.contains('active'), vms) == 1) return;
this.active = !this.active; this.active = !this.active;
}, },
@@ -179,50 +180,50 @@ export default Vue.extend({
} }
}).then(({ canceled, result: name }) => { }).then(({ canceled, result: name }) => {
if (canceled) return; if (canceled) return;
this.$store.commit('device/renameDeckColumn', { id: this.column.id, name }); this.$store.commit('renameDeckColumn', { id: this.column.id, name });
}); });
} }
}, null, { }, null, {
icon: 'arrow-left', icon: 'arrow-left',
text: this.$t('swap-left'), text: this.$t('swap-left'),
action: () => { action: () => {
this.$store.commit('device/swapLeftDeckColumn', this.column.id); this.$store.commit('swapLeftDeckColumn', this.column.id);
} }
}, { }, {
icon: 'arrow-right', icon: 'arrow-right',
text: this.$t('swap-right'), text: this.$t('swap-right'),
action: () => { action: () => {
this.$store.commit('device/swapRightDeckColumn', this.column.id); this.$store.commit('swapRightDeckColumn', this.column.id);
} }
}, this.isStacked ? { }, this.isStacked ? {
icon: faArrowUp, icon: faArrowUp,
text: this.$t('swap-up'), text: this.$t('swap-up'),
action: () => { action: () => {
this.$store.commit('device/swapUpDeckColumn', this.column.id); this.$store.commit('swapUpDeckColumn', this.column.id);
} }
} : undefined, this.isStacked ? { } : undefined, this.isStacked ? {
icon: faArrowDown, icon: faArrowDown,
text: this.$t('swap-down'), text: this.$t('swap-down'),
action: () => { action: () => {
this.$store.commit('device/swapDownDeckColumn', this.column.id); this.$store.commit('swapDownDeckColumn', this.column.id);
} }
} : undefined, null, { } : undefined, null, {
icon: ['far', 'window-restore'], icon: ['far', 'window-restore'],
text: this.$t('stack-left'), text: this.$t('stack-left'),
action: () => { action: () => {
this.$store.commit('device/stackLeftDeckColumn', this.column.id); this.$store.commit('stackLeftDeckColumn', this.column.id);
} }
}, this.isStacked ? { }, this.isStacked ? {
icon: faWindowMaximize, icon: faWindowMaximize,
text: this.$t('pop-right'), text: this.$t('pop-right'),
action: () => { action: () => {
this.$store.commit('device/popRightDeckColumn', this.column.id); this.$store.commit('popRightDeckColumn', this.column.id);
} }
} : undefined, null, { } : undefined, null, {
icon: ['far', 'trash-alt'], icon: ['far', 'trash-alt'],
text: this.$t('remove'), text: this.$t('remove'),
action: () => { action: () => {
this.$store.commit('device/removeDeckColumn', this.column.id); this.$store.commit('removeDeckColumn', this.column.id);
} }
}]; }];
@@ -306,7 +307,7 @@ export default Vue.extend({
const id = e.dataTransfer.getData('mk-deck-column'); const id = e.dataTransfer.getData('mk-deck-column');
if (id != null && id != '') { if (id != null && id != '') {
this.$store.commit('device/swapDeckColumn', { this.$store.commit('swapDeckColumn', {
a: this.column.id, a: this.column.id,
b: id b: id
}); });

View File

@@ -73,6 +73,9 @@ export default Vue.extend({
enabled: true enabled: true
}, },
}, },
dataLabels: {
enabled: false
},
grid: { grid: {
clipMarkers: false, clipMarkers: false,
padding: { padding: {

View File

@@ -4,15 +4,15 @@
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div> <div>
<header> <header>
<mk-reaction-icon :reaction="notification.reaction"/> <mk-reaction-icon :reaction="notification.reaction" class="icon"/>
<router-link :to="notification.user | userPage"> <router-link :to="notification.user | userPage" class="name">
<mk-user-name :user="notification.user"/> <mk-user-name :user="notification.user"/>
</router-link> </router-link>
<mk-time :time="notification.createdAt"/> <mk-time :time="notification.createdAt"/>
</header> </header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/> <fa icon="quote-left"/>
<mfm :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/> <mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/> <fa icon="quote-right"/>
</router-link> </router-link>
</div> </div>
@@ -22,15 +22,15 @@
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div> <div>
<header> <header>
<fa icon="retweet"/> <fa icon="retweet" class="icon"/>
<router-link :to="notification.user | userPage"> <router-link :to="notification.user | userPage" class="name">
<mk-user-name :user="notification.user"/> <mk-user-name :user="notification.user"/>
</router-link> </router-link>
<mk-time :time="notification.createdAt"/> <mk-time :time="notification.createdAt"/>
</header> </header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)"> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
<fa icon="quote-left"/> <fa icon="quote-left"/>
<mfm :text="getNoteSummary(notification.note.renote)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.renote.emojis"/> <mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="true" :custom-emojis="notification.note.renote.emojis"/>
<fa icon="quote-right"/> <fa icon="quote-right"/>
</router-link> </router-link>
</div> </div>
@@ -40,8 +40,8 @@
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div> <div>
<header> <header>
<fa icon="user-plus"/> <fa icon="user-plus" class="icon"/>
<router-link :to="notification.user | userPage"> <router-link :to="notification.user | userPage" class="name">
<mk-user-name :user="notification.user"/> <mk-user-name :user="notification.user"/>
</router-link> </router-link>
<mk-time :time="notification.createdAt"/> <mk-time :time="notification.createdAt"/>
@@ -53,9 +53,9 @@
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div> <div>
<header> <header>
<fa icon="user-clock"/> <fa icon="user-clock" class="icon"/>
<router-link :to="notification.user | userPage"> <router-link :to="notification.user | userPage">
<mk-user-name :user="notification.user"/> <mk-user-name :user="notification.user" class="name"/>
</router-link> </router-link>
<mk-time :time="notification.createdAt"/> <mk-time :time="notification.createdAt"/>
</header> </header>
@@ -66,15 +66,15 @@
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div> <div>
<header> <header>
<fa icon="chart-pie"/> <fa icon="chart-pie" class="icon"/>
<router-link :to="notification.user | userPage"> <router-link :to="notification.user | userPage">
<mk-user-name :user="notification.user"/> <mk-user-name :user="notification.user" class="name"/>
</router-link> </router-link>
<mk-time :time="notification.createdAt"/> <mk-time :time="notification.createdAt"/>
</header> </header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/> <fa icon="quote-left"/>
<mfm :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/> <mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/> <fa icon="quote-right"/>
</router-link> </router-link>
</div> </div>
@@ -137,9 +137,13 @@ export default Vue.extend({
align-items baseline align-items baseline
white-space nowrap white-space nowrap
[data-icon], .mk-reaction-icon > .icon
margin-right 4px margin-right 4px
> .name
overflow hidden
text-overflow ellipsis
> .mk-time > .mk-time
margin-left auto margin-left auto
color var(--noteHeaderInfo) color var(--noteHeaderInfo)

View File

@@ -0,0 +1,69 @@
<template>
<x-column>
<template #header>
<fa :icon="faStickyNote"/>{{ page ? page.name : '' }}
</template>
<div v-if="page">
<x-page :page="page" :key="page.id"/>
</div>
</x-column>
</template>
<script lang="ts">
import Vue from 'vue';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../i18n';
import XColumn from './deck.column.vue';
import XPage from '../../../common/views/components/page/page.vue';
export default Vue.extend({
i18n: i18n(),
components: {
XColumn,
XPage
},
props: {
pageName: {
type: String,
required: true
},
username: {
type: String,
required: true
},
},
data() {
return {
page: null,
faStickyNote
};
},
watch: {
$route: 'fetch'
},
created() {
this.fetch();
},
methods: {
fetch() {
this.$root.api('pages/show', {
name: this.pageName,
username: this.username,
}).then(page => {
this.page = page;
this.$emit('init', {
title: this.page.title,
icon: faStickyNote
});
});
}
}
});
</script>

View File

@@ -90,7 +90,7 @@ export default Vue.extend({
methods: { methods: {
onChangeSettings(v) { onChangeSettings(v) {
this.$store.commit('device/updateDeckColumn', this.column); this.$store.commit('updateDeckColumn', this.column);
}, },
focus() { focus() {

View File

@@ -1,5 +1,11 @@
<template> <template>
<div> <div>
<ui-container v-if="user.pinnedPage" :body-togglable="true">
<template #header><fa icon="thumbtack"/> {{ $t('pinned-page') }}</template>
<div>
<x-page :page="user.pinnedPage" :key="user.pinnedPage.id" :show-title="!user.pinnedPage.hideTitleWhenPinned"/>
</div>
</ui-container>
<ui-container v-if="user.pinnedNotes && user.pinnedNotes.length > 0" :body-togglable="true"> <ui-container v-if="user.pinnedNotes && user.pinnedNotes.length > 0" :body-togglable="true">
<template #header><fa icon="thumbtack"/> {{ $t('pinned-notes') }}</template> <template #header><fa icon="thumbtack"/> {{ $t('pinned-notes') }}</template>
<div> <div>
@@ -48,6 +54,7 @@ export default Vue.extend({
components: { components: {
XNotes, XNotes,
XPage: () => import('../../../common/views/components/page/page.vue').then(m => m.default),
}, },
props: { props: {
@@ -97,7 +104,9 @@ export default Vue.extend({
const image = [ const image = [
'image/jpeg', 'image/jpeg',
'image/png', 'image/png',
'image/gif' 'image/gif',
'image/apng',
'image/vnd.mozilla.apng',
]; ];
this.$root.api('users/notes', { this.$root.api('users/notes', {
@@ -161,6 +170,9 @@ export default Vue.extend({
columnWidth: '80%' columnWidth: '80%'
} }
}, },
dataLabels: {
enabled: false
},
grid: { grid: {
clipMarkers: false, clipMarkers: false,
padding: { padding: {

View File

@@ -30,7 +30,7 @@
<div class="fields" v-if="user.fields"> <div class="fields" v-if="user.fields">
<dl class="field" v-for="(field, i) in user.fields" :key="i"> <dl class="field" v-for="(field, i) in user.fields" :key="i">
<dt class="name"> <dt class="name">
<mfm :text="field.name" :should-break="false" :plain-text="true" :custom-emojis="user.emojis"/> <mfm :text="field.name" :plain="true" :custom-emojis="user.emojis"/>
</dt> </dt>
<dd class="value"> <dd class="value">
<mfm :text="field.value" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> <mfm :text="field.value" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>

View File

@@ -25,20 +25,25 @@ import * as uuid from 'uuid';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('deck'), i18n: i18n('deck'),
components: { components: {
XColumnCore XColumnCore
}, },
computed: { computed: {
deck() {
return this.$store.getters.deck;
},
columns(): any[] { columns(): any[] {
if (this.$store.state.device.deck == null) return []; if (this.deck == null) return [];
return this.$store.state.device.deck.columns; return this.deck.columns;
}, },
layout(): any[] { layout(): any[] {
if (this.$store.state.device.deck == null) return []; if (this.deck == null) return [];
if (this.$store.state.device.deck.layout == null) return this.$store.state.device.deck.columns.map(c => [c.id]); if (this.deck.layout == null) return this.deck.columns.map(c => [c.id]);
return this.$store.state.device.deck.layout; return this.deck.layout;
}, },
style(): any { style(): any {
@@ -75,7 +80,7 @@ export default Vue.extend({
}, },
created() { created() {
if (this.$store.state.device.deck == null) { if (this.deck == null) {
const deck = { const deck = {
columns: [/*{ columns: [/*{
type: 'widgets', type: 'widgets',
@@ -101,10 +106,7 @@ export default Vue.extend({
deck.layout = deck.columns.map(c => [c.id]); deck.layout = deck.columns.map(c => [c.id]);
this.$store.commit('device/set', { this.$store.commit('setDeck', deck);
key: 'deck',
value: deck
});
} }
}, },
@@ -129,7 +131,7 @@ export default Vue.extend({
icon: 'home', icon: 'home',
text: this.$t('@deck.home'), text: this.$t('@deck.home'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'home' type: 'home'
}); });
@@ -138,7 +140,7 @@ export default Vue.extend({
icon: ['far', 'comments'], icon: ['far', 'comments'],
text: this.$t('@deck.local'), text: this.$t('@deck.local'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'local' type: 'local'
}); });
@@ -147,7 +149,7 @@ export default Vue.extend({
icon: 'share-alt', icon: 'share-alt',
text: this.$t('@deck.hybrid'), text: this.$t('@deck.hybrid'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'hybrid' type: 'hybrid'
}); });
@@ -156,7 +158,7 @@ export default Vue.extend({
icon: 'globe', icon: 'globe',
text: this.$t('@deck.global'), text: this.$t('@deck.global'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'global' type: 'global'
}); });
@@ -165,7 +167,7 @@ export default Vue.extend({
icon: 'at', icon: 'at',
text: this.$t('@deck.mentions'), text: this.$t('@deck.mentions'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'mentions' type: 'mentions'
}); });
@@ -174,7 +176,7 @@ export default Vue.extend({
icon: ['far', 'envelope'], icon: ['far', 'envelope'],
text: this.$t('@deck.direct'), text: this.$t('@deck.direct'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'direct' type: 'direct'
}); });
@@ -195,7 +197,7 @@ export default Vue.extend({
showCancelButton: true showCancelButton: true
}); });
if (canceled) return; if (canceled) return;
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'list', type: 'list',
list: lists.find(l => l.id === listId) list: lists.find(l => l.id === listId)
@@ -210,7 +212,7 @@ export default Vue.extend({
input: true input: true
}).then(({ canceled, result: title }) => { }).then(({ canceled, result: title }) => {
if (canceled) return; if (canceled) return;
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'hashtag', type: 'hashtag',
tagTlId: this.$store.state.settings.tagTimelines.find(x => x.title == title).id tagTlId: this.$store.state.settings.tagTimelines.find(x => x.title == title).id
@@ -221,7 +223,7 @@ export default Vue.extend({
icon: ['far', 'bell'], icon: ['far', 'bell'],
text: this.$t('@deck.notifications'), text: this.$t('@deck.notifications'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'notifications' type: 'notifications'
}); });
@@ -230,7 +232,7 @@ export default Vue.extend({
icon: 'calculator', icon: 'calculator',
text: this.$t('@deck.widgets'), text: this.$t('@deck.widgets'),
action: () => { action: () => {
this.$store.commit('device/addDeckColumn', { this.$store.commit('addDeckColumn', {
id: uuid(), id: uuid(),
type: 'widgets', type: 'widgets',
widgets: [] widgets: []

View File

@@ -110,7 +110,7 @@ export default Vue.extend({
}, },
addWidget() { addWidget() {
this.$store.commit('device/addDeckWidget', { this.$store.commit('addDeckWidget', {
id: this.column.id, id: this.column.id,
widget: { widget: {
name: this.widgetAdderSelected, name: this.widgetAdderSelected,
@@ -123,14 +123,14 @@ export default Vue.extend({
}, },
removeWidget(widget) { removeWidget(widget) {
this.$store.commit('device/removeDeckWidget', { this.$store.commit('removeDeckWidget', {
id: this.column.id, id: this.column.id,
widget widget
}); });
}, },
saveWidgets() { saveWidgets() {
this.$store.commit('device/updateDeckColumn', this.column); this.$store.commit('updateDeckColumn', this.column);
} }
} }
}); });

View File

@@ -2,7 +2,7 @@ import Vue from 'vue';
Vue.filter('bytes', (v, digits = 0) => { Vue.filter('bytes', (v, digits = 0) => {
if (v == null) return '?'; if (v == null) return '?';
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
if (v == 0) return '0'; if (v == 0) return '0';
const isMinus = v < 0; const isMinus = v < 0;
if (isMinus) v = -v; if (isMinus) v = -v;

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching"> <div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching">
<div class="signed-in-as"> <div class="signed-in-as">
<mfm :text="$t('signed-in-as').replace('{}', myName)" :should-break="false" :plain-text="true" :custom-emojis="$store.state.i.emojis"/> <mfm :text="$t('signed-in-as').replace('{}', myName)" :plain="true" :custom-emojis="$store.state.i.emojis"/>
</div> </div>
<main> <main>
<div class="banner" :style="bannerStyle"></div> <div class="banner" :style="bannerStyle"></div>

View File

@@ -4,12 +4,31 @@
<section class="xfhsjczc"> <section class="xfhsjczc">
<ui-input v-model="value.text"><span>{{ $t('blocks._button.text') }}</span></ui-input> <ui-input v-model="value.text"><span>{{ $t('blocks._button.text') }}</span></ui-input>
<ui-switch v-model="value.primary"><span>{{ $t('blocks._button.colored') }}</span></ui-switch>
<ui-select v-model="value.action"> <ui-select v-model="value.action">
<template #label>{{ $t('blocks._button.action') }}</template> <template #label>{{ $t('blocks._button.action') }}</template>
<option value="dialog">{{ $t('blocks._button._action.dialog') }}</option> <option value="dialog">{{ $t('blocks._button._action.dialog') }}</option>
<option value="resetRandom">{{ $t('blocks._button._action.resetRandom') }}</option> <option value="resetRandom">{{ $t('blocks._button._action.resetRandom') }}</option>
<option value="pushEvent">{{ $t('blocks._button._action.pushEvent') }}</option>
</ui-select> </ui-select>
<ui-input v-if="value.action === 'dialog'" v-model="value.content"><span>{{ $t('blocks._button._action._dialog.content') }}</span></ui-input> <template v-if="value.action === 'dialog'">
<ui-input v-model="value.content"><span>{{ $t('blocks._button._action._dialog.content') }}</span></ui-input>
</template>
<template v-else-if="value.action === 'pushEvent'">
<ui-input v-model="value.event"><span>{{ $t('blocks._button._action._pushEvent.event') }}</span></ui-input>
<ui-input v-model="value.message"><span>{{ $t('blocks._button._action._pushEvent.message') }}</span></ui-input>
<ui-select v-model="value.var">
<template #label>{{ $t('blocks._button._action._pushEvent.variable') }}</template>
<option :value="null">{{ $t('blocks._button._action._pushEvent.no-variable') }}</option>
<option v-for="v in aiScript.getVarsByType()" :value="v.name">{{ v.name }}</option>
<optgroup :label="$t('script.pageVariables')">
<option v-for="v in aiScript.getPageVarsByType()" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$t('script.enviromentVariables')">
<option v-for="v in aiScript.getEnvVarsByType()" :value="v">{{ v }}</option>
</optgroup>
</ui-select>
</template>
</section> </section>
</x-container> </x-container>
</template> </template>
@@ -31,6 +50,9 @@ export default Vue.extend({
value: { value: {
required: true required: true
}, },
aiScript: {
required: true,
},
}, },
data() { data() {
@@ -43,6 +65,10 @@ export default Vue.extend({
if (this.value.text == null) Vue.set(this.value, 'text', ''); if (this.value.text == null) Vue.set(this.value, 'text', '');
if (this.value.action == null) Vue.set(this.value, 'action', 'dialog'); if (this.value.action == null) Vue.set(this.value, 'action', 'dialog');
if (this.value.content == null) Vue.set(this.value, 'content', null); if (this.value.content == null) Vue.set(this.value, 'content', null);
if (this.value.event == null) Vue.set(this.value, 'event', null);
if (this.value.message == null) Vue.set(this.value, 'message', null);
if (this.value.primary == null) Vue.set(this.value, 'primary', false);
if (this.value.var == null) Vue.set(this.value, 'var', null);
}, },
}); });
</script> </script>

View File

@@ -35,6 +35,8 @@
<option value="sans-serif">{{ $t('fontSansSerif') }}</option> <option value="sans-serif">{{ $t('fontSansSerif') }}</option>
</ui-select> </ui-select>
<ui-switch v-model="hideTitleWhenPinned">{{ $t('hide-title-when-pinned') }}</ui-switch>
<div class="eyeCatch"> <div class="eyeCatch">
<ui-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('set-eye-catching-image') }}</ui-button> <ui-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('set-eye-catching-image') }}</ui-button>
<div v-else-if="eyeCatchingImage"> <div v-else-if="eyeCatchingImage">
@@ -140,6 +142,7 @@ export default Vue.extend({
font: 'sans-serif', font: 'sans-serif',
content: [], content: [],
alignCenter: false, alignCenter: false,
hideTitleWhenPinned: false,
variables: [], variables: [],
aiScript: null, aiScript: null,
showOptions: false, showOptions: false,
@@ -192,6 +195,7 @@ export default Vue.extend({
this.currentName = this.page.name; this.currentName = this.page.name;
this.summary = this.page.summary; this.summary = this.page.summary;
this.font = this.page.font; this.font = this.page.font;
this.hideTitleWhenPinned = this.page.hideTitleWhenPinned;
this.alignCenter = this.page.alignCenter; this.alignCenter = this.page.alignCenter;
this.content = this.page.content; this.content = this.page.content;
this.variables = this.page.variables; this.variables = this.page.variables;
@@ -223,6 +227,7 @@ export default Vue.extend({
name: this.name.trim(), name: this.name.trim(),
summary: this.summary, summary: this.summary,
font: this.font, font: this.font,
hideTitleWhenPinned: this.hideTitleWhenPinned,
alignCenter: this.alignCenter, alignCenter: this.alignCenter,
content: this.content, content: this.content,
variables: this.variables, variables: this.variables,
@@ -240,6 +245,7 @@ export default Vue.extend({
name: this.name.trim(), name: this.name.trim(),
summary: this.summary, summary: this.summary,
font: this.font, font: this.font,
hideTitleWhenPinned: this.hideTitleWhenPinned,
alignCenter: this.alignCenter, alignCenter: this.alignCenter,
content: this.content, content: this.content,
variables: this.variables, variables: this.variables,

View File

@@ -0,0 +1,63 @@
<template>
<x-page v-if="page" :page="page" :key="page.id" :show-footer="true"/>
</template>
<script lang="ts">
import Vue from 'vue';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
import XPage from '../components/page/page.vue';
export default Vue.extend({
components: {
XPage
},
props: {
pageName: {
type: String,
required: true
},
username: {
type: String,
required: true
},
},
data() {
return {
page: null,
};
},
computed: {
path(): string {
return this.username + '/' + this.pageName;
}
},
watch: {
path() {
this.fetch();
}
},
created() {
this.fetch();
},
methods: {
fetch() {
this.$root.api('pages/show', {
name: this.pageName,
username: this.username,
}).then(page => {
this.page = page;
this.$emit('init', {
title: this.page.title,
icon: faStickyNote
});
});
},
}
});
</script>

View File

@@ -38,6 +38,7 @@
import define from '../../../common/define-widget'; import define from '../../../common/define-widget';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import insertTextAtCursor from 'insert-text-at-cursor'; import insertTextAtCursor from 'insert-text-at-cursor';
import { formatTimeString } from '../../../../../misc/format-time-string';
export default define({ export default define({
name: 'post-form', name: 'post-form',
@@ -109,10 +110,23 @@ export default define({
if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey) && !this.posting && this.text) this.post(); if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey) && !this.posting && this.text) this.post();
}, },
onPaste(e) { async onPaste(e: ClipboardEvent) {
for (const item of Array.from(e.clipboardData.items)) { for (const { item, i } of Array.from(e.clipboardData.items).map((item, i) => ({item, i}))) {
if (item.kind == 'file') { if (item.kind == 'file') {
this.upload(item.getAsFile()); const file = item.getAsFile();
const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : '';
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.settings.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
const name = this.$store.state.settings.pasteDialog
? await this.$root.dialog({
title: this.$t('@.post-form.enter-file-name'),
input: {
default: formatted
},
allowEmpty: false
}).then(({ canceled, result }) => canceled ? false : result)
: formatted;
if (name) this.upload(file, name);
} }
} }
}, },
@@ -121,8 +135,8 @@ export default define({
for (const x of Array.from((this.$refs.file as any).files)) this.upload(x); for (const x of Array.from((this.$refs.file as any).files)) this.upload(x);
}, },
upload(file) { upload(file: File, name?: string) {
(this.$refs.uploader as any).upload(file); (this.$refs.uploader as any).upload(file, this.$store.state.settings.uploadFolder, name);
}, },
onDragover(e) { onDragover(e) {

View File

@@ -90,6 +90,9 @@ export default define({
enabled: true, enabled: true,
} }
}, },
dataLabels: {
enabled: false
},
tooltip: { tooltip: {
enabled: false enabled: false
}, },

View File

@@ -3,6 +3,8 @@
<p>Maintainer: <b><a :href="'mailto:' + meta.maintainerEmail" target="_blank">{{ meta.maintainerName }}</a></b></p> <p>Maintainer: <b><a :href="'mailto:' + meta.maintainerEmail" target="_blank">{{ meta.maintainerName }}</a></b></p>
<p>Machine: {{ meta.machine }}</p> <p>Machine: {{ meta.machine }}</p>
<p>Node: {{ meta.node }}</p> <p>Node: {{ meta.node }}</p>
<p>PSQL: {{ meta.psql }}</p>
<p>Redis: {{ meta.redis }}</p>
<p>Version: {{ meta.version }} </p> <p>Version: {{ meta.version }} </p>
</div> </div>
</template> </template>

View File

@@ -91,6 +91,7 @@ export default ($root: any) => {
? Promise.resolve(file) ? Promise.resolve(file)
: $root.$chooseDriveFile({ : $root.$chooseDriveFile({
multiple: false, multiple: false,
type: 'image/*',
title: locale['desktop']['choose-avatar'] title: locale['desktop']['choose-avatar']
}); });

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