Compare commits

...

271 Commits

Author SHA1 Message Date
khr 537c2bde02 Cybrespace locale 2019-06-23 15:50:16 -07:00
Eugen Rochko 66ac1bd063
Fix unconverted PRs in the changelog (#11155) 2019-06-22 18:13:52 +02:00
Eugen Rochko b5c772c3d4
Bump version to 2.9.2 (#11152) 2019-06-22 17:28:26 +02:00
Eugen Rochko 8fe7116cdf
New Crowdin translations (#11144)
* New translations simple_form.en.yml (Japanese)
[ci skip]

* New translations en.json (Catalan)
[ci skip]

* New translations doorkeeper.en.yml (Catalan)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Galician)
[ci skip]

* New translations en.json (Arabic)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-22 17:26:09 +02:00
Eugen Rochko b927bb3f07
Fix audio-only OGG and WebM files not being processed as such (#11151)
Also, because Chrome sends audio/mp3 instead of audio/mpeg as it's
supposed to, we need to whitelist that mime type as well
2019-06-22 16:54:06 +02:00
koyu 6eb5241099 Change camera icon to paperclip icon in upload form (#11149) 2019-06-22 15:29:25 +02:00
Eugen Rochko d61d164685
Add `short_description` and `approval_required` to `GET /api/v1/instance` (#11146) 2019-06-22 12:08:16 +02:00
Eugen Rochko aa9b37822b
Fix audio not being downloaded from remote servers (#11145) 2019-06-22 02:50:36 +02:00
Eugen Rochko 84f945d64c
Bump version to 2.9.1 (#11143) 2019-06-22 01:51:27 +02:00
Eugen Rochko 6e7e714bd9
New Crowdin translations (#11116)
* New translations devise.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations devise.en.yml (Chinese Traditional)
[ci skip]

* New translations activerecord.en.yml (Thai)
[ci skip]

* New translations activerecord.en.yml (Slovak)
[ci skip]

* New translations activerecord.en.yml (French)
[ci skip]

* New translations activerecord.en.yml (Hungarian)
[ci skip]

* New translations activerecord.en.yml (Hebrew)
[ci skip]

* New translations activerecord.en.yml (Greek)
[ci skip]

* New translations activerecord.en.yml (German)
[ci skip]

* New translations activerecord.en.yml (Georgian)
[ci skip]

* New translations activerecord.en.yml (Galician)
[ci skip]

* New translations activerecord.en.yml (Esperanto)
[ci skip]

* New translations activerecord.en.yml (Danish)
[ci skip]

* New translations activerecord.en.yml (Czech)
[ci skip]

* New translations activerecord.en.yml (Corsican)
[ci skip]

* New translations activerecord.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations activerecord.en.yml (Indonesian)
[ci skip]

* New translations activerecord.en.yml (Japanese)
[ci skip]

* New translations activerecord.en.yml (Swedish)
[ci skip]

* New translations activerecord.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations activerecord.en.yml (Spanish)
[ci skip]

* New translations activerecord.en.yml (Slovenian)
[ci skip]

* New translations devise.en.yml (Ido)
[ci skip]

* New translations activerecord.en.yml (Serbian (Latin))
[ci skip]

* New translations activerecord.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations activerecord.en.yml (Russian)
[ci skip]

* New translations activerecord.en.yml (Portuguese)
[ci skip]

* New translations activerecord.en.yml (Kazakh)
[ci skip]

* New translations activerecord.en.yml (Polish)
[ci skip]

* New translations activerecord.en.yml (Persian)
[ci skip]

* New translations activerecord.en.yml (Occitan)
[ci skip]

* New translations activerecord.en.yml (Norwegian)
[ci skip]

* New translations activerecord.en.yml (Korean)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Indonesian)
[ci skip]

* New translations doorkeeper.en.yml (Ido)
[ci skip]

* New translations doorkeeper.en.yml (Korean)
[ci skip]

* New translations doorkeeper.en.yml (Kazakh)
[ci skip]

* New translations doorkeeper.en.yml (Japanese)
[ci skip]

* New translations doorkeeper.en.yml (Indonesian)
[ci skip]

* New translations doorkeeper.en.yml (Hungarian)
[ci skip]

* New translations doorkeeper.en.yml (Norwegian)
[ci skip]

* New translations doorkeeper.en.yml (Hebrew)
[ci skip]

* New translations doorkeeper.en.yml (Greek)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations doorkeeper.en.yml (Georgian)
[ci skip]

* New translations doorkeeper.en.yml (Galician)
[ci skip]

* New translations doorkeeper.en.yml (French)
[ci skip]

* New translations doorkeeper.en.yml (Finnish)
[ci skip]

* New translations doorkeeper.en.yml (Occitan)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Ukrainian)
[ci skip]

* New translations doorkeeper.en.yml (Turkish)
[ci skip]

* New translations doorkeeper.en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Swedish)
[ci skip]

* New translations doorkeeper.en.yml (Spanish)
[ci skip]

* New translations doorkeeper.en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Persian)
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Latin))
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations doorkeeper.en.yml (Russian)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese)
[ci skip]

* New translations doorkeeper.en.yml (Polish)
[ci skip]

* New translations doorkeeper.en.yml (Esperanto)
[ci skip]

* New translations doorkeeper.en.yml (Danish)
[ci skip]

* New translations devise.en.yml (Persian)
[ci skip]

* New translations devise.en.yml (Serbian (Latin))
[ci skip]

* New translations devise.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations devise.en.yml (Russian)
[ci skip]

* New translations devise.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations devise.en.yml (Portuguese)
[ci skip]

* New translations devise.en.yml (Polish)
[ci skip]

* New translations devise.en.yml (Occitan)
[ci skip]

* New translations devise.en.yml (Slovenian)
[ci skip]

* New translations devise.en.yml (Norwegian)
[ci skip]

* New translations activerecord.en.yml (Chinese Simplified)
[ci skip]

* New translations devise.en.yml (Korean)
[ci skip]

* New translations devise.en.yml (Kazakh)
[ci skip]

* New translations devise.en.yml (Japanese)
[ci skip]

* New translations devise.en.yml (Slovak)
[ci skip]

* New translations devise.en.yml (Spanish)
[ci skip]

* New translations doorkeeper.en.yml (Czech)
[ci skip]

* New translations doorkeeper.en.yml (Croatian)
[ci skip]

* New translations doorkeeper.en.yml (Corsican)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Traditional)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Simplified)
[ci skip]

* New translations doorkeeper.en.yml (Catalan)
[ci skip]

* New translations doorkeeper.en.yml (Bulgarian)
[ci skip]

* New translations doorkeeper.en.yml (Basque)
[ci skip]

* New translations devise.en.yml (Swedish)
[ci skip]

* New translations doorkeeper.en.yml (Asturian)
[ci skip]

* New translations devise.en.yml (Welsh)
[ci skip]

* New translations devise.en.yml (Ukrainian)
[ci skip]

* New translations devise.en.yml (Turkish)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations activerecord.en.yml (Catalan)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.yml (Bulgarian)
[ci skip]

* New translations en.yml (Bengali)
[ci skip]

* New translations en.yml (Basque)
[ci skip]

* New translations en.json (Ukrainian)
[ci skip]

* New translations en.json (Turkish)
[ci skip]

* New translations en.json (Telugu)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.json (Tamil)
[ci skip]

* New translations en.json (Swedish)
[ci skip]

* New translations en.json (Spanish)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovak)
[ci skip]

* New translations en.json (Serbian (Latin))
[ci skip]

* New translations en.json (Serbian (Cyrillic))
[ci skip]

* New translations en.yml (Catalan)
[ci skip]

* New translations en.yml (Chinese Traditional)
[ci skip]

* New translations en.json (Romanian)
[ci skip]

* New translations en.yml (Georgian)
[ci skip]

* New translations en.yml (Indonesian)
[ci skip]

* New translations en.yml (Ido)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hebrew)
[ci skip]

* New translations en.yml (Greek)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations en.yml (Galician)
[ci skip]

* New translations en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.yml (French)
[ci skip]

* New translations en.yml (Finnish)
[ci skip]

* New translations en.yml (Esperanto)
[ci skip]

* New translations en.yml (Danish)
[ci skip]

* New translations en.yml (Croatian)
[ci skip]

* New translations en.yml (Corsican)
[ci skip]

* New translations en.json (Portuguese, Brazilian)
[ci skip]

* New translations en.json (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations en.json (Danish)
[ci skip]

* New translations en.json (Croatian)
[ci skip]

* New translations en.json (Chinese Traditional)
[ci skip]

* New translations en.json (Catalan)
[ci skip]

* New translations en.json (Bulgarian)
[ci skip]

* New translations en.json (Bengali)
[ci skip]

* New translations devise.en.yml (Czech)
[ci skip]

* New translations simple_form.en.yml (Czech)
[ci skip]

* New translations en.json (Georgian)
[ci skip]

* New translations en.json (Portuguese)
[ci skip]

* New translations en.json (Occitan)
[ci skip]

* New translations en.json (Norwegian)
[ci skip]

* New translations en.json (Malay)
[ci skip]

* New translations en.json (Lithuanian)
[ci skip]

* New translations en.json (Latvian)
[ci skip]

* New translations en.json (Kazakh)
[ci skip]

* New translations en.json (Indonesian)
[ci skip]

* New translations en.json (Ido)
[ci skip]

* New translations en.json (Hebrew)
[ci skip]

* New translations en.yml (Kazakh)
[ci skip]

* New translations simple_form.en.yml (Occitan)
[ci skip]

* New translations simple_form.en.yml (Norwegian)
[ci skip]

* New translations simple_form.en.yml (Korean)
[ci skip]

* New translations simple_form.en.yml (Japanese)
[ci skip]

* New translations simple_form.en.yml (Polish)
[ci skip]

* New translations simple_form.en.yml (Indonesian)
[ci skip]

* New translations simple_form.en.yml (Ido)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Hebrew)
[ci skip]

* New translations simple_form.en.yml (Greek)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations simple_form.en.yml (Persian)
[ci skip]

* New translations simple_form.en.yml (Portuguese)
[ci skip]

* New translations simple_form.en.yml (Galician)
[ci skip]

* New translations activerecord.en.yml (Basque)
[ci skip]

* New translations en.yml (Czech)
[ci skip]

* New translations simple_form.en.yml (Ukrainian)
[ci skip]

* New translations simple_form.en.yml (Turkish)
[ci skip]

* New translations simple_form.en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Swedish)
[ci skip]

* New translations simple_form.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations simple_form.en.yml (Spanish)
[ci skip]

* New translations simple_form.en.yml (Slovenian)
[ci skip]

* New translations simple_form.en.yml (Slovak)
[ci skip]

* New translations simple_form.en.yml (Serbian (Latin))
[ci skip]

* New translations simple_form.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations simple_form.en.yml (Russian)
[ci skip]

* New translations simple_form.en.yml (Romanian)
[ci skip]

* New translations simple_form.en.yml (Georgian)
[ci skip]

* New translations simple_form.en.yml (French)
[ci skip]

* New translations en.yml (Korean)
[ci skip]

* New translations en.yml (Portuguese, Brazilian)
[ci skip]

* New translations en.yml (Slovenian)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Serbian (Latin))
[ci skip]

* New translations en.yml (Serbian (Cyrillic))
[ci skip]

* New translations en.yml (Russian)
[ci skip]

* New translations en.yml (Romanian)
[ci skip]

* New translations en.yml (Portuguese)
[ci skip]

* New translations en.yml (Swedish)
[ci skip]

* New translations en.yml (Polish)
[ci skip]

* New translations en.yml (Persian)
[ci skip]

* New translations en.yml (Occitan)
[ci skip]

* New translations en.yml (Norwegian)
[ci skip]

* New translations en.yml (Malay)
[ci skip]

* New translations en.yml (Lithuanian)
[ci skip]

* New translations en.yml (Latvian)
[ci skip]

* New translations en.yml (Spanish)
[ci skip]

* New translations en.yml (Tamil)
[ci skip]

* New translations simple_form.en.yml (Finnish)
[ci skip]

* New translations simple_form.en.yml (Chinese Simplified)
[ci skip]

* New translations simple_form.en.yml (Esperanto)
[ci skip]

* New translations simple_form.en.yml (Danish)
[ci skip]

* New translations simple_form.en.yml (Croatian)
[ci skip]

* New translations simple_form.en.yml (Corsican)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional)
[ci skip]

* New translations simple_form.en.yml (Catalan)
[ci skip]

* New translations en.yml (Telugu)
[ci skip]

* New translations simple_form.en.yml (Bulgarian)
[ci skip]

* New translations simple_form.en.yml (Basque)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations en.yml (Ukrainian)
[ci skip]

* New translations en.yml (Turkish)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Japanese)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations activerecord.en.yml (Finnish)
[ci skip]

* New translations en.json (Japanese)
[ci skip]

* New translations doorkeeper.en.yml (Japanese)
[ci skip]

* New translations doorkeeper.en.yml (Greek)
[ci skip]

* New translations doorkeeper.en.yml (Italian)
[ci skip]

* New translations doorkeeper.en.yml (Italian)
[ci skip]

* New translations en.yml (Italian)
[ci skip]

* New translations en.json (Slovak)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Polish)
[ci skip]

* New translations doorkeeper.en.yml (Czech)
[ci skip]

* New translations doorkeeper.en.yml (Corsican)
[ci skip]

* New translations doorkeeper.en.yml (Corsican)
[ci skip]

* New translations en.yml (Italian)
[ci skip]

* New translations en.json (Italian)
[ci skip]

* New translations en.yml (Italian)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Polish)
[ci skip]

* New translations en.json (Dutch)
[ci skip]

* New translations en.json (German)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-22 00:57:48 +02:00
Eugen Rochko 1b052c7b2d
Remove expensive counters from federation page in admin UI (#11139) 2019-06-22 00:39:09 +02:00
Eugen Rochko 707ddf7808
Change domain blocks to automatically support subdomains (#11138)
* Change domain blocks to automatically support subdomains

If a more authoritative domain is blocked (example.com), then the
same block will be applied to a subdomain (foo.example.com)

* Match subdomains of existing accounts when blocking/unblocking domains

* Improve code style
2019-06-22 00:13:10 +02:00
Eugen Rochko 49ebda4d49
Change audio format from ogg to mp3 for wider compatibility (#11141)
* Change audio format from ogg to mp3 for wider compatibility

* Add media description as title to links of unknown media attachments
2019-06-21 22:59:44 +02:00
Eugen Rochko 8f23726918
Fix converted media being saved with original extension and mime type (#11130) 2019-06-20 10:52:36 +02:00
Eugen Rochko 7696f77245
Add moderation API (#9387)
Fix #8580
Fix #7143
2019-06-20 02:52:34 +02:00
Acid Chicken (硫酸鶏) 33144e132d Fix layout of identity proofs settings (#11126) 2019-06-20 02:18:06 +02:00
Eugen Rochko f7f23b4a19
Add audio uploads (#11123)
* Add audio uploads

Fix #4827

Accept uploads of OGG, WAV, FLAC, OPUS and MP3 files, and converts
them to OGG. Media attachments get a new `audio` type. In the UI,
audio uploads are displayed identically to video uploads.

* Improve code style
2019-06-19 23:42:38 +02:00
Eugen Rochko e9a11dca19
Fix inconsistent interpolation in sk.yml (#11124) 2019-06-19 18:25:06 +02:00
Alix Rossi 26d3b2efce Add label for admin theme selector (#11121)
* Add simple_form default for admin theme selector

* Revert "Add simple_form default for admin theme selector"

This reverts commit 0b736f78a87d61075f9b9f774d8da80e1e897b47.

* Add setting_theme label to admin theme selector
2019-06-19 17:30:08 +02:00
Eugen Rochko ede0be5dba
New Crowdin translations (#11077)
* New translations en.json (Persian)
[ci skip]

* New translations en.yml (Dutch)
[ci skip]

* New translations simple_form.en.yml (Dutch)
[ci skip]

* New translations activerecord.en.yml (Dutch)
[ci skip]

* New translations devise.en.yml (Dutch)
[ci skip]

* New translations doorkeeper.en.yml (Dutch)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Czech)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.json (Czech)
[ci skip]

* New translations en.json (Greek)
[ci skip]

* New translations simple_form.en.yml (Greek)
[ci skip]

* New translations en.json (Greek)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Persian)
[ci skip]

* New translations en.json (Persian)
[ci skip]

* New translations en.yml (Persian)
[ci skip]

* New translations simple_form.en.yml (Persian)
[ci skip]

* New translations simple_form.en.yml (Persian)
[ci skip]

* New translations simple_form.en.yml (Persian)
[ci skip]

* New translations activerecord.en.yml (Persian)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations en.yml (Japanese)
[ci skip]

* New translations en.yml (Japanese)
[ci skip]

* New translations en.json (Bengali)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations simple_form.en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations activerecord.en.yml (Welsh)
[ci skip]

* New translations devise.en.yml (Welsh)
[ci skip]

* New translations en.json (Welsh)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations devise.en.yml (Welsh)
[ci skip]

* New translations doorkeeper.en.yml (Welsh)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations activerecord.en.yml (Thai)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Thai)
[ci skip]

* New translations en.json (Slovak)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Slovak)
[ci skip]

* New translations devise.en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Thai)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations activerecord.en.yml (Thai)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.json (Arabic)
[ci skip]

* New translations en.yml (Arabic)
[ci skip]

* New translations devise.en.yml (Arabic)
[ci skip]

* New translations doorkeeper.en.yml (Arabic)
[ci skip]

* New translations doorkeeper.en.yml (Welsh)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations activerecord.en.yml (Japanese)
[ci skip]

* New translations devise.en.yml (Japanese)
[ci skip]

* New translations doorkeeper.en.yml (Japanese)
[ci skip]

* New translations simple_form.en.yml (Japanese)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Thai)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.json (Corsican)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations activerecord.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations en.yml (Japanese)
[ci skip]

* New translations en.yml (Japanese)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations doorkeeper.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations doorkeeper.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.json (Arabic)
[ci skip]

* New translations en.yml (Arabic)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.json (Spanish)
[ci skip]

* New translations en.yml (Spanish)
[ci skip]

* New translations en.json (Basque)
[ci skip]

* New translations en.yml (Basque)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations activerecord.en.yml (Hungarian)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-18 22:58:18 +02:00
ThibG c8fae508cf Completely hide toots matched by “irreversible” filters even if they got to the client (#11113)
Fixes #11090
2019-06-18 18:23:08 +02:00
ThibG 17747e2cd7 Fix User#active scope only returning suspended users (#11111)
Fix a regression from #10660
2019-06-18 18:22:02 +02:00
dependabot-preview[bot] 83dd4d4204 Bump enzyme-adapter-react-16 from 1.7.1 to 1.14.0 (#11105)
Bumps [enzyme-adapter-react-16](https://github.com/airbnb/enzyme/tree/HEAD/packages/enzyme-adapter-react-16) from 1.7.1 to 1.14.0.
- [Release notes](https://github.com/airbnb/enzyme/releases)
- [Changelog](https://github.com/airbnb/enzyme/blob/master/CHANGELOG.md)
- [Commits](https://github.com/airbnb/enzyme/commits/enzyme-adapter-react-16@1.14.0/packages/enzyme-adapter-react-16)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-18 00:28:28 +09:00
dependabot-preview[bot] b403c33fb4 Bump webpack-cli from 3.3.2 to 3.3.4 (#11106)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 3.3.2 to 3.3.4.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/v3.3.2...v3.3.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-18 00:20:54 +09:00
dependabot-preview[bot] 7555a0017e Bump webpack from 4.29.6 to 4.34.0 (#11108)
Bumps [webpack](https://github.com/webpack/webpack) from 4.29.6 to 4.34.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.29.6...v4.34.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-18 00:19:00 +09:00
dependabot-preview[bot] 85ec79cedf Bump enzyme from 3.8.0 to 3.10.0 (#11107)
Bumps [enzyme](https://github.com/airbnb/enzyme/tree/HEAD/packages/enzyme) from 3.8.0 to 3.10.0.
- [Release notes](https://github.com/airbnb/enzyme/releases)
- [Changelog](https://github.com/airbnb/enzyme/blob/master/CHANGELOG.md)
- [Commits](https://github.com/airbnb/enzyme/commits/enzyme@3.10.0/packages/enzyme)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-18 00:04:24 +09:00
dependabot-preview[bot] 54438042f1 Bump capybara from 3.22.0 to 3.24.0 (#11100)
Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.22.0 to 3.24.0.
- [Release notes](https://github.com/teamcapybara/capybara/releases)
- [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md)
- [Commits](https://github.com/teamcapybara/capybara/compare/3.22.0...3.24.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 23:23:13 +09:00
dependabot-preview[bot] 119cb4d473 Bump file-loader from 3.0.1 to 4.0.0 (#11104)
Bumps [file-loader](https://github.com/webpack-contrib/file-loader) from 3.0.1 to 4.0.0.
- [Release notes](https://github.com/webpack-contrib/file-loader/releases)
- [Changelog](https://github.com/webpack-contrib/file-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/file-loader/compare/v3.0.1...v4.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 23:14:52 +09:00
dependabot-preview[bot] 9639a7f87a Bump ox from 2.10.1 to 2.11.0 (#11101)
Bumps ox from 2.10.1 to 2.11.0.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 22:50:20 +09:00
dependabot-preview[bot] 10c4c21298 Bump lograge from 0.11.1 to 0.11.2 (#11102)
Bumps [lograge](https://github.com/roidrage/lograge) from 0.11.1 to 0.11.2.
- [Release notes](https://github.com/roidrage/lograge/releases)
- [Changelog](https://github.com/roidrage/lograge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/roidrage/lograge/compare/v0.11.1...v0.11.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:23:29 +09:00
dependabot-preview[bot] f4539845e0 Bump webmock from 3.5.1 to 3.6.0 (#11031)
Bumps [webmock](https://github.com/bblimke/webmock) from 3.5.1 to 3.6.0.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.5.1...v3.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:17:45 +09:00
dependabot-preview[bot] 31eed31e37 Bump rellax from 1.7.1 to 1.10.0 (#11040)
Bumps [rellax](https://github.com/dixonandmoe/rellax) from 1.7.1 to 1.10.0.
- [Release notes](https://github.com/dixonandmoe/rellax/releases)
- [Commits](https://github.com/dixonandmoe/rellax/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:17:32 +09:00
dependabot-preview[bot] efb07f177d Bump webpack-bundle-analyzer from 3.1.0 to 3.3.2 (#11039)
Bumps [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) from 3.1.0 to 3.3.2.
- [Release notes](https://github.com/webpack-contrib/webpack-bundle-analyzer/releases)
- [Changelog](https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/webpack-bundle-analyzer/compare/v3.1.0...v3.3.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:17:11 +09:00
dependabot-preview[bot] bab2231470 Bump autoprefixer from 9.5.1 to 9.6.0 (#11038)
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 9.5.1 to 9.6.0.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/9.5.1...9.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:17:02 +09:00
dependabot-preview[bot] a9ba6a880e Bump eslint-plugin-import from 2.14.0 to 2.17.3 (#11037)
Bumps [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import) from 2.14.0 to 2.17.3.
- [Release notes](https://github.com/benmosher/eslint-plugin-import/releases)
- [Changelog](https://github.com/benmosher/eslint-plugin-import/blob/master/CHANGELOG.md)
- [Commits](https://github.com/benmosher/eslint-plugin-import/compare/v2.14.0...v2.17.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:16:47 +09:00
dependabot-preview[bot] e67f38020f Bump httplog from 1.3.0 to 1.3.1 (#11034)
Bumps [httplog](https://github.com/trusche/httplog) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/trusche/httplog/releases)
- [Changelog](https://github.com/trusche/httplog/blob/master/CHANGELOG.md)
- [Commits](https://github.com/trusche/httplog/compare/v1.3.0...v1.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:16:22 +09:00
dependabot-preview[bot] 04b4d2b4fa Bump pghero from 2.2.0 to 2.2.1 (#11033)
Bumps [pghero](https://github.com/ankane/pghero) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/ankane/pghero/releases)
- [Changelog](https://github.com/ankane/pghero/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ankane/pghero/compare/v2.2.0...v2.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:16:15 +09:00
dependabot-preview[bot] 7b058c5687 Bump rubocop-rails from 2.0.0 to 2.0.1 (#11032)
Bumps [rubocop-rails](https://github.com/rubocop-hq/rubocop-rails) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/rubocop-hq/rubocop-rails/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop-rails/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop-rails/compare/v2.0.0...v2.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:16:03 +09:00
dependabot-preview[bot] f765cd97b2 Bump aws-sdk-s3 from 1.41.0 to 1.42.0 (#11030)
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.41.0 to 1.42.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/compare/v1.41.0...v1.42.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-17 21:15:33 +09:00
Eugen Rochko 103a9f4466
Fix sanitizer making block level elements unreadable (#10836)
Fix #10834
2019-06-16 21:46:36 +02:00
Eugen Rochko 65efe892cf
Fix check-i18n builds (#11084)
* Fix check-i18n builds

* Remove check for missing plural forms
2019-06-16 19:12:12 +02:00
ThibG 01e362316c Do not scroll in the compose panel on single-column (#11093) 2019-06-16 18:46:55 +02:00
Yusuke Nakamura 0828126784 Update translating platform has changed to crowdin (CONTRIBUTING.md) (#11094)
Restore and change from 89096860
2019-06-16 18:36:47 +02:00
Dan Hunsaker 54192a9b6f Resync Nanobox files with the 2.9.0 release (#11083) 2019-06-14 14:52:31 +02:00
Eugen Rochko c9eeb2e832
Bump version to 2.9.0 (#11074) 2019-06-13 20:19:21 +02:00
Eugen Rochko 5c7f1e8e2f
New Crowdin translations (#11075)
* New translations en.json (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations en.yml (Korean)
[ci skip]

* New translations en.yml (Esperanto)
[ci skip]

* New translations simple_form.en.yml (Esperanto)
[ci skip]

* i18n-tasks normalize
2019-06-13 20:17:56 +02:00
Eugen Rochko e6024d610d
New Crowdin translations (#11073)
* New translations en.json (Arabic)
[ci skip]

* New translations en.yml (Arabic)
[ci skip]

* New translations simple_form.en.yml (Arabic)
[ci skip]

* New translations en.json (Arabic)
[ci skip]

* New translations en.yml (Arabic)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations simple_form.en.yml (Arabic)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-13 18:05:51 +02:00
ThibG b4d67fe57a Fix ordering of keyboard access between CW field, textarea and emoji picker (#11066) 2019-06-13 17:07:43 +02:00
ThibG dd45c63921 List attachments in reply indicator and boost modal (#10997)
* Add media attachments list to boost modal

* Add attachment list to reply indicator
2019-06-13 17:04:52 +02:00
Eugen Rochko 917f0ea619
New Crowdin translations (#11069)
* New translations en.json (Ukrainian)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.yml (Bulgarian)
[ci skip]

* New translations en.json (Telugu)
[ci skip]

* New translations en.json (Tamil)
[ci skip]

* New translations en.json (Swedish)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Slovak)
[ci skip]

* New translations en.json (Serbian (Latin))
[ci skip]

* New translations en.json (Serbian (Cyrillic))
[ci skip]

* New translations en.yml (Catalan)
[ci skip]

* New translations en.json (Romanian)
[ci skip]

* New translations en.yml (Georgian)
[ci skip]

* New translations en.yml (Czech)
[ci skip]

* New translations en.yml (Indonesian)
[ci skip]

* New translations en.yml (Ido)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hebrew)
[ci skip]

* New translations en.yml (Galician)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (French)
[ci skip]

* New translations en.yml (Finnish)
[ci skip]

* New translations en.yml (Esperanto)
[ci skip]

* New translations en.yml (Dutch)
[ci skip]

* New translations en.yml (Danish)
[ci skip]

* New translations en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.yml (Chinese Traditional)
[ci skip]

* New translations en.yml (Croatian)
[ci skip]

* New translations en.json (Portuguese, Brazilian)
[ci skip]

* New translations en.json (Danish)
[ci skip]

* New translations en.json (Croatian)
[ci skip]

* New translations en.json (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.json (Chinese Traditional)
[ci skip]

* New translations en.json (Catalan)
[ci skip]

* New translations en.json (Asturian)
[ci skip]

* New translations en.json (Armenian)
[ci skip]

* New translations en.json (Albanian)
[ci skip]

* New translations en.json (Portuguese)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations en.json (Bulgarian)
[ci skip]

* New translations en.json (Kazakh)
[ci skip]

* New translations en.json (Georgian)
[ci skip]

* New translations en.json (Persian)
[ci skip]

* New translations en.json (Occitan)
[ci skip]

* New translations en.json (Norwegian)
[ci skip]

* New translations en.json (Lithuanian)
[ci skip]

* New translations en.json (Latvian)
[ci skip]

* New translations en.json (Malay)
[ci skip]

* New translations en.json (Indonesian)
[ci skip]

* New translations en.json (Ido)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Hebrew)
[ci skip]

* New translations en.json (Italian)
[ci skip]

* New translations activerecord.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations devise.en.yml (Kazakh)
[ci skip]

* New translations devise.en.yml (Japanese)
[ci skip]

* New translations devise.en.yml (Italian)
[ci skip]

* New translations devise.en.yml (Indonesian)
[ci skip]

* New translations devise.en.yml (Hebrew)
[ci skip]

* New translations devise.en.yml (Ido)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Greek)
[ci skip]

* New translations devise.en.yml (Georgian)
[ci skip]

* New translations devise.en.yml (German)
[ci skip]

* New translations devise.en.yml (Korean)
[ci skip]

* New translations devise.en.yml (Norwegian)
[ci skip]

* New translations devise.en.yml (Occitan)
[ci skip]

* New translations devise.en.yml (Persian)
[ci skip]

* New translations devise.en.yml (Polish)
[ci skip]

* New translations devise.en.yml (Portuguese)
[ci skip]

* New translations devise.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations devise.en.yml (Russian)
[ci skip]

* New translations devise.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations devise.en.yml (Serbian (Latin))
[ci skip]

* New translations devise.en.yml (French)
[ci skip]

* New translations devise.en.yml (Slovak)
[ci skip]

* New translations devise.en.yml (Galician)
[ci skip]

* New translations activerecord.en.yml (Turkish)
[ci skip]

* New translations devise.en.yml (Finnish)
[ci skip]

* New translations devise.en.yml (Arabic)
[ci skip]

* New translations devise.en.yml (Spanish)
[ci skip]

* New translations activerecord.en.yml (Serbian (Latin))
[ci skip]

* New translations activerecord.en.yml (Slovak)
[ci skip]

* New translations activerecord.en.yml (Slovenian)
[ci skip]

* New translations activerecord.en.yml (Spanish)
[ci skip]

* New translations activerecord.en.yml (Swedish)
[ci skip]

* New translations activerecord.en.yml (Thai)
[ci skip]

* New translations activerecord.en.yml (Ukrainian)
[ci skip]

* New translations activerecord.en.yml (Welsh)
[ci skip]

* New translations devise.en.yml (Albanian)
[ci skip]

* New translations devise.en.yml (Esperanto)
[ci skip]

* New translations devise.en.yml (Asturian)
[ci skip]

* New translations devise.en.yml (Basque)
[ci skip]

* New translations devise.en.yml (Bulgarian)
[ci skip]

* New translations devise.en.yml (Catalan)
[ci skip]

* New translations devise.en.yml (Chinese Simplified)
[ci skip]

* New translations devise.en.yml (Chinese Traditional)
[ci skip]

* New translations devise.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations devise.en.yml (Corsican)
[ci skip]

* New translations devise.en.yml (Croatian)
[ci skip]

* New translations devise.en.yml (Danish)
[ci skip]

* New translations devise.en.yml (Dutch)
[ci skip]

* New translations devise.en.yml (Slovenian)
[ci skip]

* New translations devise.en.yml (Swedish)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese)
[ci skip]

* New translations doorkeeper.en.yml (Indonesian)
[ci skip]

* New translations doorkeeper.en.yml (Italian)
[ci skip]

* New translations doorkeeper.en.yml (Japanese)
[ci skip]

* New translations doorkeeper.en.yml (Kazakh)
[ci skip]

* New translations doorkeeper.en.yml (Norwegian)
[ci skip]

* New translations doorkeeper.en.yml (Occitan)
[ci skip]

* New translations doorkeeper.en.yml (Persian)
[ci skip]

* New translations doorkeeper.en.yml (Polish)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations doorkeeper.en.yml (Hungarian)
[ci skip]

* New translations doorkeeper.en.yml (Russian)
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Latin))
[ci skip]

* New translations doorkeeper.en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Spanish)
[ci skip]

* New translations doorkeeper.en.yml (Swedish)
[ci skip]

* New translations doorkeeper.en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Turkish)
[ci skip]

* New translations doorkeeper.en.yml (Ukrainian)
[ci skip]

* New translations doorkeeper.en.yml (Ido)
[ci skip]

* New translations doorkeeper.en.yml (Hebrew)
[ci skip]

* New translations doorkeeper.en.yml (Catalan)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations devise.en.yml (Turkish)
[ci skip]

* New translations devise.en.yml (Ukrainian)
[ci skip]

* New translations devise.en.yml (Welsh)
[ci skip]

* New translations doorkeeper.en.yml (Albanian)
[ci skip]

* New translations doorkeeper.en.yml (Arabic)
[ci skip]

* New translations doorkeeper.en.yml (Asturian)
[ci skip]

* New translations doorkeeper.en.yml (Bulgarian)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Simplified)
[ci skip]

* New translations doorkeeper.en.yml (Greek)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Traditional)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations doorkeeper.en.yml (Corsican)
[ci skip]

* New translations doorkeeper.en.yml (Croatian)
[ci skip]

* New translations doorkeeper.en.yml (Czech)
[ci skip]

* New translations doorkeeper.en.yml (Danish)
[ci skip]

* New translations doorkeeper.en.yml (Dutch)
[ci skip]

* New translations doorkeeper.en.yml (Esperanto)
[ci skip]

* New translations doorkeeper.en.yml (Finnish)
[ci skip]

* New translations doorkeeper.en.yml (French)
[ci skip]

* New translations doorkeeper.en.yml (Galician)
[ci skip]

* New translations doorkeeper.en.yml (Georgian)
[ci skip]

* New translations activerecord.en.yml (Russian)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations activerecord.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations simple_form.en.yml (Dutch)
[ci skip]

* New translations simple_form.en.yml (Asturian)
[ci skip]

* New translations simple_form.en.yml (Basque)
[ci skip]

* New translations simple_form.en.yml (Bulgarian)
[ci skip]

* New translations simple_form.en.yml (Catalan)
[ci skip]

* New translations simple_form.en.yml (Chinese Simplified)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations simple_form.en.yml (Corsican)
[ci skip]

* New translations simple_form.en.yml (Croatian)
[ci skip]

* New translations simple_form.en.yml (Danish)
[ci skip]

* New translations simple_form.en.yml (Esperanto)
[ci skip]

* New translations simple_form.en.yml (Albanian)
[ci skip]

* New translations simple_form.en.yml (Finnish)
[ci skip]

* New translations simple_form.en.yml (French)
[ci skip]

* New translations simple_form.en.yml (Galician)
[ci skip]

* New translations simple_form.en.yml (Georgian)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations simple_form.en.yml (Hebrew)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Ido)
[ci skip]

* New translations simple_form.en.yml (Indonesian)
[ci skip]

* New translations simple_form.en.yml (Italian)
[ci skip]

* New translations simple_form.en.yml (Japanese)
[ci skip]

* New translations simple_form.en.yml (Arabic)
[ci skip]

* New translations simple_form.en.yml (Korean)
[ci skip]

* New translations simple_form.en.yml (Czech)
[ci skip]

* New translations devise.en.yml (Czech)
[ci skip]

* New translations en.yml (Italian)
[ci skip]

* New translations en.yml (Kazakh)
[ci skip]

* New translations en.yml (Latvian)
[ci skip]

* New translations en.yml (Lithuanian)
[ci skip]

* New translations en.yml (Malay)
[ci skip]

* New translations en.yml (Norwegian)
[ci skip]

* New translations en.yml (Occitan)
[ci skip]

* New translations en.yml (Persian)
[ci skip]

* New translations en.yml (Portuguese)
[ci skip]

* New translations en.yml (Ukrainian)
[ci skip]

* New translations en.yml (Portuguese, Brazilian)
[ci skip]

* New translations en.yml (Romanian)
[ci skip]

* New translations en.yml (Russian)
[ci skip]

* New translations en.yml (Serbian (Cyrillic))
[ci skip]

* New translations en.yml (Serbian (Latin))
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Slovenian)
[ci skip]

* New translations en.yml (Spanish)
[ci skip]

* New translations en.yml (Swedish)
[ci skip]

* New translations en.yml (Tamil)
[ci skip]

* New translations en.yml (Telugu)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Turkish)
[ci skip]

* New translations activerecord.en.yml (Portuguese)
[ci skip]

* New translations activerecord.en.yml (Hebrew)
[ci skip]

* New translations activerecord.en.yml (Corsican)
[ci skip]

* New translations activerecord.en.yml (Czech)
[ci skip]

* New translations activerecord.en.yml (Danish)
[ci skip]

* New translations activerecord.en.yml (Dutch)
[ci skip]

* New translations activerecord.en.yml (Esperanto)
[ci skip]

* New translations activerecord.en.yml (French)
[ci skip]

* New translations activerecord.en.yml (Galician)
[ci skip]

* New translations activerecord.en.yml (Georgian)
[ci skip]

* New translations activerecord.en.yml (German)
[ci skip]

* New translations activerecord.en.yml (Greek)
[ci skip]

* New translations activerecord.en.yml (Indonesian)
[ci skip]

* New translations activerecord.en.yml (Italian)
[ci skip]

* New translations activerecord.en.yml (Japanese)
[ci skip]

* New translations activerecord.en.yml (Kazakh)
[ci skip]

* New translations activerecord.en.yml (Norwegian)
[ci skip]

* New translations activerecord.en.yml (Occitan)
[ci skip]

* New translations activerecord.en.yml (Persian)
[ci skip]

* New translations activerecord.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations activerecord.en.yml (Chinese Simplified)
[ci skip]

* New translations simple_form.en.yml (Slovenian)
[ci skip]

* New translations simple_form.en.yml (Norwegian)
[ci skip]

* New translations simple_form.en.yml (Occitan)
[ci skip]

* New translations simple_form.en.yml (Persian)
[ci skip]

* New translations simple_form.en.yml (Portuguese)
[ci skip]

* New translations simple_form.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations simple_form.en.yml (Romanian)
[ci skip]

* New translations simple_form.en.yml (Russian)
[ci skip]

* New translations simple_form.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations simple_form.en.yml (Serbian (Latin))
[ci skip]

* New translations simple_form.en.yml (Slovak)
[ci skip]

* New translations simple_form.en.yml (Spanish)
[ci skip]

* New translations activerecord.en.yml (Catalan)
[ci skip]

* New translations simple_form.en.yml (Swedish)
[ci skip]

* New translations simple_form.en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Turkish)
[ci skip]

* New translations simple_form.en.yml (Ukrainian)
[ci skip]

* New translations activerecord.en.yml (Albanian)
[ci skip]

* New translations activerecord.en.yml (Arabic)
[ci skip]

* New translations activerecord.en.yml (Asturian)
[ci skip]

* New translations activerecord.en.yml (Basque)
[ci skip]

* New translations en.json (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-13 16:49:19 +02:00
Eugen Rochko 275f09ccab
Bump version to 2.9.0rc2 (#11070) 2019-06-13 00:43:59 +02:00
ThibG a4a502e85c Do not expand toot when clicking on a poll option (#11067)
Fixes regression introduced by e9ddd5a159
2019-06-13 00:16:46 +02:00
ThibG 1b4dcc3f78 Only show profile directory link when it's enabled (#11064) 2019-06-13 00:16:27 +02:00
ThibG c98573fdf9 Add button to conveniently copy OAuth code (#11065) 2019-06-13 00:14:42 +02:00
ThibG faafc3ae25 Fix border-bottom of active tab bars (#11068) 2019-06-13 00:14:27 +02:00
Eugen Rochko 809d1faa49
New Crowdin translations (#11062)
* New translations doorkeeper.en.yml (French)
[ci skip]

* New translations doorkeeper.en.yml (Corsican)
[ci skip]

* New translations doorkeeper.en.yml (Finnish)
[ci skip]

* New translations doorkeeper.en.yml (Esperanto)
[ci skip]

* New translations doorkeeper.en.yml (Dutch)
[ci skip]

* New translations doorkeeper.en.yml (Danish)
[ci skip]

* New translations doorkeeper.en.yml (Czech)
[ci skip]

* New translations doorkeeper.en.yml (Croatian)
[ci skip]

* New translations activerecord.en.yml (Asturian)
[ci skip]

* New translations activerecord.en.yml (Arabic)
[ci skip]

* New translations en.yml (Danish)
[ci skip]

* New translations simple_form.en.yml (Dutch)
[ci skip]

* New translations devise.en.yml (Georgian)
[ci skip]

* New translations devise.en.yml (Galician)
[ci skip]

* New translations devise.en.yml (French)
[ci skip]

* New translations devise.en.yml (Finnish)
[ci skip]

* New translations devise.en.yml (Dutch)
[ci skip]

* New translations devise.en.yml (Danish)
[ci skip]

* New translations devise.en.yml (Croatian)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations simple_form.en.yml (Georgian)
[ci skip]

* New translations simple_form.en.yml (Galician)
[ci skip]

* New translations simple_form.en.yml (French)
[ci skip]

* New translations simple_form.en.yml (Finnish)
[ci skip]

* New translations simple_form.en.yml (Esperanto)
[ci skip]

* New translations simple_form.en.yml (Danish)
[ci skip]

* New translations activerecord.en.yml (Albanian)
[ci skip]

* New translations simple_form.en.yml (Basque)
[ci skip]

* New translations en.yml (Czech)
[ci skip]

* New translations devise.en.yml (Corsican)
[ci skip]

* New translations simple_form.en.yml (Albanian)
[ci skip]

* New translations simple_form.en.yml (Asturian)
[ci skip]

* New translations simple_form.en.yml (Croatian)
[ci skip]

* New translations simple_form.en.yml (Bulgarian)
[ci skip]

* New translations simple_form.en.yml (Catalan)
[ci skip]

* New translations simple_form.en.yml (Chinese Simplified)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations simple_form.en.yml (Corsican)
[ci skip]

* New translations en.yml (Dutch)
[ci skip]

* New translations en.yml (Croatian)
[ci skip]

* New translations en.json (Croatian)
[ci skip]

* New translations devise.en.yml (Asturian)
[ci skip]

* New translations en.yml (Corsican)
[ci skip]

* New translations en.json (German)
[ci skip]

* New translations en.json (Georgian)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations en.json (Danish)
[ci skip]

* New translations en.json (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.json (Chinese Traditional)
[ci skip]

* New translations en.json (Bulgarian)
[ci skip]

* New translations en.json (Bengali)
[ci skip]

* New translations en.json (Asturian)
[ci skip]

* New translations en.json (Armenian)
[ci skip]

* New translations devise.en.yml (Czech)
[ci skip]

* New translations simple_form.en.yml (Czech)
[ci skip]

* New translations devise.en.yml (Basque)
[ci skip]

* New translations devise.en.yml (Albanian)
[ci skip]

* New translations devise.en.yml (Bulgarian)
[ci skip]

* New translations en.yml (Armenian)
[ci skip]

* New translations devise.en.yml (Catalan)
[ci skip]

* New translations activerecord.en.yml (Corsican)
[ci skip]

* New translations activerecord.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.yml (Asturian)
[ci skip]

* New translations activerecord.en.yml (Danish)
[ci skip]

* New translations en.yml (Basque)
[ci skip]

* New translations en.yml (Bengali)
[ci skip]

* New translations en.yml (Bulgarian)
[ci skip]

* New translations en.yml (Catalan)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Traditional)
[ci skip]

* New translations en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations activerecord.en.yml (Czech)
[ci skip]

* New translations activerecord.en.yml (Dutch)
[ci skip]

* New translations devise.en.yml (Chinese Traditional)
[ci skip]

* New translations activerecord.en.yml (French)
[ci skip]

* New translations activerecord.en.yml (Galician)
[ci skip]

* New translations devise.en.yml (Chinese Simplified)
[ci skip]

* New translations activerecord.en.yml (Georgian)
[ci skip]

* New translations activerecord.en.yml (German)
[ci skip]

* New translations devise.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations devise.en.yml (Ido)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Hebrew)
[ci skip]

* New translations devise.en.yml (Greek)
[ci skip]

* New translations devise.en.yml (German)
[ci skip]

* New translations devise.en.yml (Italian)
[ci skip]

* New translations activerecord.en.yml (Welsh)
[ci skip]

* New translations activerecord.en.yml (Ukrainian)
[ci skip]

* New translations activerecord.en.yml (Turkish)
[ci skip]

* New translations activerecord.en.yml (Thai)
[ci skip]

* New translations activerecord.en.yml (Swedish)
[ci skip]

* New translations devise.en.yml (Indonesian)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations doorkeeper.en.yml (Italian)
[ci skip]

* New translations doorkeeper.en.yml (Kazakh)
[ci skip]

* New translations doorkeeper.en.yml (Norwegian)
[ci skip]

* New translations doorkeeper.en.yml (Occitan)
[ci skip]

* New translations doorkeeper.en.yml (Persian)
[ci skip]

* New translations doorkeeper.en.yml (Polish)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese)
[ci skip]

* New translations doorkeeper.en.yml (Ido)
[ci skip]

* New translations doorkeeper.en.yml (Russian)
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Latin))
[ci skip]

* New translations doorkeeper.en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Swedish)
[ci skip]

* New translations doorkeeper.en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Turkish)
[ci skip]

* New translations doorkeeper.en.yml (Ukrainian)
[ci skip]

* New translations doorkeeper.en.yml (Indonesian)
[ci skip]

* New translations doorkeeper.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Kazakh)
[ci skip]

* New translations devise.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations devise.en.yml (Korean)
[ci skip]

* New translations devise.en.yml (Norwegian)
[ci skip]

* New translations devise.en.yml (Occitan)
[ci skip]

* New translations devise.en.yml (Persian)
[ci skip]

* New translations devise.en.yml (Polish)
[ci skip]

* New translations devise.en.yml (Portuguese)
[ci skip]

* New translations devise.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations devise.en.yml (Russian)
[ci skip]

* New translations devise.en.yml (Serbian (Latin))
[ci skip]

* New translations doorkeeper.en.yml (Hebrew)
[ci skip]

* New translations devise.en.yml (Slovak)
[ci skip]

* New translations devise.en.yml (Slovenian)
[ci skip]

* New translations devise.en.yml (Swedish)
[ci skip]

* New translations activerecord.en.yml (Slovak)
[ci skip]

* New translations devise.en.yml (Turkish)
[ci skip]

* New translations devise.en.yml (Ukrainian)
[ci skip]

* New translations devise.en.yml (Welsh)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations doorkeeper.en.yml (Greek)
[ci skip]

* New translations activerecord.en.yml (Slovenian)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations activerecord.en.yml (Serbian (Latin))
[ci skip]

* New translations en.yml (Latvian)
[ci skip]

* New translations en.json (Ukrainian)
[ci skip]

* New translations en.yml (Greek)
[ci skip]

* New translations en.yml (Hebrew)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Ido)
[ci skip]

* New translations en.yml (Indonesian)
[ci skip]

* New translations en.yml (Italian)
[ci skip]

* New translations en.yml (Kazakh)
[ci skip]

* New translations en.yml (Korean)
[ci skip]

* New translations en.yml (Lithuanian)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.yml (Malay)
[ci skip]

* New translations en.yml (Norwegian)
[ci skip]

* New translations en.yml (Occitan)
[ci skip]

* New translations en.yml (Persian)
[ci skip]

* New translations en.yml (Polish)
[ci skip]

* New translations en.yml (Portuguese)
[ci skip]

* New translations en.yml (Portuguese, Brazilian)
[ci skip]

* New translations en.yml (Romanian)
[ci skip]

* New translations en.yml (Russian)
[ci skip]

* New translations en.yml (Serbian (Cyrillic))
[ci skip]

* New translations en.yml (Serbian (Latin))
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.json (Turkish)
[ci skip]

* New translations en.json (Telugu)
[ci skip]

* New translations en.json (Norwegian)
[ci skip]

* New translations en.json (Hebrew)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.json (Ido)
[ci skip]

* New translations en.json (Indonesian)
[ci skip]

* New translations en.json (Italian)
[ci skip]

* New translations en.json (Kazakh)
[ci skip]

* New translations en.json (Korean)
[ci skip]

* New translations en.json (Latvian)
[ci skip]

* New translations en.json (Lithuanian)
[ci skip]

* New translations en.json (Malay)
[ci skip]

* New translations en.json (Occitan)
[ci skip]

* New translations en.json (Tamil)
[ci skip]

* New translations en.json (Persian)
[ci skip]

* New translations en.json (Polish)
[ci skip]

* New translations en.json (Portuguese)
[ci skip]

* New translations en.json (Portuguese, Brazilian)
[ci skip]

* New translations en.json (Romanian)
[ci skip]

* New translations en.json (Serbian (Cyrillic))
[ci skip]

* New translations en.json (Serbian (Latin))
[ci skip]

* New translations en.json (Slovak)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Spanish)
[ci skip]

* New translations en.json (Swedish)
[ci skip]

* New translations en.yml (Slovenian)
[ci skip]

* New translations en.yml (Swedish)
[ci skip]

* New translations activerecord.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations activerecord.en.yml (Japanese)
[ci skip]

* New translations simple_form.en.yml (Swedish)
[ci skip]

* New translations simple_form.en.yml (Thai)
[ci skip]

* New translations simple_form.en.yml (Turkish)
[ci skip]

* New translations simple_form.en.yml (Ukrainian)
[ci skip]

* New translations activerecord.en.yml (Greek)
[ci skip]

* New translations activerecord.en.yml (Hebrew)
[ci skip]

* New translations activerecord.en.yml (Indonesian)
[ci skip]

* New translations activerecord.en.yml (Italian)
[ci skip]

* New translations activerecord.en.yml (Kazakh)
[ci skip]

* New translations simple_form.en.yml (Slovenian)
[ci skip]

* New translations activerecord.en.yml (Norwegian)
[ci skip]

* New translations activerecord.en.yml (Occitan)
[ci skip]

* New translations activerecord.en.yml (Persian)
[ci skip]

* New translations activerecord.en.yml (Polish)
[ci skip]

* New translations activerecord.en.yml (Portuguese)
[ci skip]

* New translations activerecord.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations activerecord.en.yml (Russian)
[ci skip]

* New translations simple_form.en.yml (Slovak)
[ci skip]

* New translations en.yml (Tamil)
[ci skip]

* New translations en.yml (Telugu)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Turkish)
[ci skip]

* New translations en.yml (Ukrainian)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Greek)
[ci skip]

* New translations simple_form.en.yml (Hebrew)
[ci skip]

* New translations simple_form.en.yml (Hungarian)
[ci skip]

* New translations simple_form.en.yml (Ido)
[ci skip]

* New translations simple_form.en.yml (Indonesian)
[ci skip]

* New translations simple_form.en.yml (Italian)
[ci skip]

* New translations simple_form.en.yml (Korean)
[ci skip]

* New translations simple_form.en.yml (Serbian (Latin))
[ci skip]

* New translations simple_form.en.yml (Norwegian)
[ci skip]

* New translations simple_form.en.yml (Occitan)
[ci skip]

* New translations simple_form.en.yml (Persian)
[ci skip]

* New translations simple_form.en.yml (Polish)
[ci skip]

* New translations simple_form.en.yml (Portuguese)
[ci skip]

* New translations simple_form.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations simple_form.en.yml (Romanian)
[ci skip]

* New translations simple_form.en.yml (Russian)
[ci skip]

* New translations simple_form.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations doorkeeper.en.yml (Welsh)
[ci skip]

* New translations en.json (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations en.json (Russian)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations simple_form.en.yml (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations en.yml (German)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-12 23:46:19 +02:00
Eugen Rochko 1390da501d
Change translations badge in README to Crowdin (#11054) 2019-06-12 15:56:41 +02:00
Eugen Rochko 481cc19d4d
New Crowdin translations (#11060)
* New translations devise.en.yml (Chinese Traditional)
[ci skip]

* New translations devise.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations devise.en.yml (Corsican)
[ci skip]

* New translations devise.en.yml (Croatian)
[ci skip]

* New translations devise.en.yml (Danish)
[ci skip]

* New translations devise.en.yml (Dutch)
[ci skip]

* New translations devise.en.yml (Esperanto)
[ci skip]

* New translations devise.en.yml (Finnish)
[ci skip]

* New translations devise.en.yml (French)
[ci skip]

* New translations devise.en.yml (Galician)
[ci skip]

* New translations devise.en.yml (Georgian)
[ci skip]

* New translations devise.en.yml (German)
[ci skip]

* New translations activerecord.en.yml (Tamil)
[ci skip]

* New translations activerecord.en.yml (Spanish)
[ci skip]

* New translations activerecord.en.yml (French)
[ci skip]

* New translations activerecord.en.yml (Latvian)
[ci skip]

* New translations activerecord.en.yml (Galician)
[ci skip]

* New translations activerecord.en.yml (Georgian)
[ci skip]

* New translations activerecord.en.yml (German)
[ci skip]

* New translations activerecord.en.yml (Greek)
[ci skip]

* New translations activerecord.en.yml (Hebrew)
[ci skip]

* New translations activerecord.en.yml (Hungarian)
[ci skip]

* New translations activerecord.en.yml (Ido)
[ci skip]

* New translations activerecord.en.yml (Indonesian)
[ci skip]

* New translations activerecord.en.yml (Italian)
[ci skip]

* New translations activerecord.en.yml (Japanese)
[ci skip]

* New translations activerecord.en.yml (Kazakh)
[ci skip]

* New translations activerecord.en.yml (Korean)
[ci skip]

* New translations activerecord.en.yml (Lithuanian)
[ci skip]

* New translations activerecord.en.yml (Slovenian)
[ci skip]

* New translations activerecord.en.yml (Malay)
[ci skip]

* New translations activerecord.en.yml (Norwegian)
[ci skip]

* New translations activerecord.en.yml (Occitan)
[ci skip]

* New translations activerecord.en.yml (Persian)
[ci skip]

* New translations activerecord.en.yml (Polish)
[ci skip]

* New translations activerecord.en.yml (Portuguese)
[ci skip]

* New translations activerecord.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations activerecord.en.yml (Romanian)
[ci skip]

* New translations activerecord.en.yml (Russian)
[ci skip]

* New translations activerecord.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations activerecord.en.yml (Serbian (Latin))
[ci skip]

* New translations activerecord.en.yml (Slovak)
[ci skip]

* New translations simple_form.en.yml (Corsican)
[ci skip]

* New translations simple_form.en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Chinese Traditional)
[ci skip]

* New translations en.json (Russian)
[ci skip]

* New translations en.json (Kazakh)
[ci skip]

* New translations en.json (Korean)
[ci skip]

* New translations en.json (Latvian)
[ci skip]

* New translations en.json (Lithuanian)
[ci skip]

* New translations en.json (Malay)
[ci skip]

* New translations en.json (Norwegian)
[ci skip]

* New translations en.json (Occitan)
[ci skip]

* New translations en.json (Persian)
[ci skip]

* New translations en.json (Polish)
[ci skip]

* New translations en.json (Portuguese)
[ci skip]

* New translations en.json (Portuguese, Brazilian)
[ci skip]

* New translations en.json (Romanian)
[ci skip]

* New translations en.json (Serbian (Cyrillic))
[ci skip]

* New translations en.json (Italian)
[ci skip]

* New translations en.json (Serbian (Latin))
[ci skip]

* New translations en.json (Slovak)
[ci skip]

* New translations en.json (Slovenian)
[ci skip]

* New translations en.json (Spanish)
[ci skip]

* New translations en.json (Swedish)
[ci skip]

* New translations en.json (Tamil)
[ci skip]

* New translations en.json (Telugu)
[ci skip]

* New translations en.json (Thai)
[ci skip]

* New translations en.json (Turkish)
[ci skip]

* New translations en.json (Ukrainian)
[ci skip]

* New translations en.json (Welsh)
[ci skip]

* New translations en.yml (Albanian)
[ci skip]

* New translations en.json (Japanese)
[ci skip]

* New translations en.json (Indonesian)
[ci skip]

* New translations en.yml (Armenian)
[ci skip]

* New translations en.json (Chinese Traditional, Hong Kong)
[ci skip]

* New translations simple_form.en.yml (Czech)
[ci skip]

* New translations devise.en.yml (Czech)
[ci skip]

* New translations en.json (Albanian)
[ci skip]

* New translations en.json (Arabic)
[ci skip]

* New translations en.json (Armenian)
[ci skip]

* New translations en.json (Asturian)
[ci skip]

* New translations en.json (Basque)
[ci skip]

* New translations en.json (Bengali)
[ci skip]

* New translations en.json (Bulgarian)
[ci skip]

* New translations en.json (Catalan)
[ci skip]

* New translations en.json (Chinese Simplified)
[ci skip]

* New translations en.json (Chinese Traditional)
[ci skip]

* New translations en.json (Corsican)
[ci skip]

* New translations en.json (Ido)
[ci skip]

* New translations en.json (Croatian)
[ci skip]

* New translations simple_form.en.yml (Chinese Simplified)
[ci skip]

* New translations en.json (Dutch)
[ci skip]

* New translations en.json (Esperanto)
[ci skip]

* New translations en.json (Finnish)
[ci skip]

* New translations en.json (French)
[ci skip]

* New translations en.json (Galician)
[ci skip]

* New translations en.json (Georgian)
[ci skip]

* New translations en.json (German)
[ci skip]

* New translations en.json (Greek)
[ci skip]

* New translations en.json (Hebrew)
[ci skip]

* New translations en.json (Hungarian)
[ci skip]

* New translations en.yml (Arabic)
[ci skip]

* New translations en.json (Danish)
[ci skip]

* New translations en.yml (Asturian)
[ci skip]

* New translations en.yml (Tamil)
[ci skip]

* New translations en.yml (Persian)
[ci skip]

* New translations en.yml (Polish)
[ci skip]

* New translations en.yml (Portuguese)
[ci skip]

* New translations en.yml (Portuguese, Brazilian)
[ci skip]

* New translations en.yml (Romanian)
[ci skip]

* New translations en.yml (Russian)
[ci skip]

* New translations en.yml (Serbian (Cyrillic))
[ci skip]

* New translations en.yml (Serbian (Latin))
[ci skip]

* New translations en.yml (Slovak)
[ci skip]

* New translations en.yml (Slovenian)
[ci skip]

* New translations en.yml (Spanish)
[ci skip]

* New translations en.yml (Swedish)
[ci skip]

* New translations en.yml (Telugu)
[ci skip]

* New translations en.yml (Norwegian)
[ci skip]

* New translations en.yml (Thai)
[ci skip]

* New translations en.yml (Turkish)
[ci skip]

* New translations en.yml (Ukrainian)
[ci skip]

* New translations en.yml (Welsh)
[ci skip]

* New translations simple_form.en.yml (Arabic)
[ci skip]

* New translations simple_form.en.yml (Armenian)
[ci skip]

* New translations simple_form.en.yml (Asturian)
[ci skip]

* New translations simple_form.en.yml (Basque)
[ci skip]

* New translations simple_form.en.yml (Bengali)
[ci skip]

* New translations simple_form.en.yml (Bulgarian)
[ci skip]

* New translations simple_form.en.yml (Catalan)
[ci skip]

* New translations en.yml (Basque)
[ci skip]

* New translations en.yml (Occitan)
[ci skip]

* New translations simple_form.en.yml (Albanian)
[ci skip]

* New translations en.yml (Malay)
[ci skip]

* New translations en.yml (French)
[ci skip]

* New translations en.yml (Bengali)
[ci skip]

* New translations en.yml (Lithuanian)
[ci skip]

* New translations en.yml (Bulgarian)
[ci skip]

* New translations en.yml (Catalan)
[ci skip]

* New translations en.yml (Chinese Simplified)
[ci skip]

* New translations en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations en.yml (Corsican)
[ci skip]

* New translations en.yml (Croatian)
[ci skip]

* New translations en.yml (Danish)
[ci skip]

* New translations en.yml (Dutch)
[ci skip]

* New translations en.yml (Esperanto)
[ci skip]

* New translations en.yml (Finnish)
[ci skip]

* New translations en.yml (Chinese Traditional)
[ci skip]

* New translations en.yml (Galician)
[ci skip]

* New translations en.yml (Indonesian)
[ci skip]

* New translations en.yml (Georgian)
[ci skip]

* New translations en.yml (Latvian)
[ci skip]

* New translations en.yml (Kazakh)
[ci skip]

* New translations en.yml (Japanese)
[ci skip]

* New translations en.yml (Italian)
[ci skip]

* New translations en.yml (Ido)
[ci skip]

* New translations en.yml (Hungarian)
[ci skip]

* New translations en.yml (Hebrew)
[ci skip]

* New translations en.yml (Greek)
[ci skip]

* New translations en.yml (German)
[ci skip]

* New translations en.yml (Korean)
[ci skip]

* New translations doorkeeper.en.yml (Kazakh)
[ci skip]

* New translations doorkeeper.en.yml (Hebrew)
[ci skip]

* New translations doorkeeper.en.yml (Korean)
[ci skip]

* New translations doorkeeper.en.yml (Japanese)
[ci skip]

* New translations doorkeeper.en.yml (Italian)
[ci skip]

* New translations doorkeeper.en.yml (Indonesian)
[ci skip]

* New translations doorkeeper.en.yml (Ido)
[ci skip]

* New translations doorkeeper.en.yml (Hungarian)
[ci skip]

* New translations doorkeeper.en.yml (Finnish)
[ci skip]

* New translations doorkeeper.en.yml (Greek)
[ci skip]

* New translations doorkeeper.en.yml (German)
[ci skip]

* New translations doorkeeper.en.yml (Georgian)
[ci skip]

* New translations doorkeeper.en.yml (Galician)
[ci skip]

* New translations doorkeeper.en.yml (French)
[ci skip]

* New translations doorkeeper.en.yml (Esperanto)
[ci skip]

* New translations doorkeeper.en.yml (Dutch)
[ci skip]

* New translations doorkeeper.en.yml (Danish)
[ci skip]

* New translations doorkeeper.en.yml (Lithuanian)
[ci skip]

* New translations doorkeeper.en.yml (Czech)
[ci skip]

* New translations doorkeeper.en.yml (Latvian)
[ci skip]

* New translations doorkeeper.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Malay)
[ci skip]

* New translations doorkeeper.en.yml (Slovak)
[ci skip]

* New translations doorkeeper.en.yml (Corsican)
[ci skip]

* New translations doorkeeper.en.yml (Ukrainian)
[ci skip]

* New translations doorkeeper.en.yml (Turkish)
[ci skip]

* New translations doorkeeper.en.yml (Thai)
[ci skip]

* New translations doorkeeper.en.yml (Telugu)
[ci skip]

* New translations doorkeeper.en.yml (Tamil)
[ci skip]

* New translations doorkeeper.en.yml (Swedish)
[ci skip]

* New translations doorkeeper.en.yml (Spanish)
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Latin))
[ci skip]

* New translations doorkeeper.en.yml (Norwegian)
[ci skip]

* New translations doorkeeper.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations doorkeeper.en.yml (Russian)
[ci skip]

* New translations doorkeeper.en.yml (Romanian)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations doorkeeper.en.yml (Portuguese)
[ci skip]

* New translations doorkeeper.en.yml (Polish)
[ci skip]

* New translations doorkeeper.en.yml (Persian)
[ci skip]

* New translations doorkeeper.en.yml (Occitan)
[ci skip]

* New translations doorkeeper.en.yml (Croatian)
[ci skip]

* New translations devise.en.yml (Persian)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Traditional, Hong Kong)
[ci skip]

* New translations devise.en.yml (Latvian)
[ci skip]

* New translations devise.en.yml (Romanian)
[ci skip]

* New translations devise.en.yml (Portuguese, Brazilian)
[ci skip]

* New translations devise.en.yml (Portuguese)
[ci skip]

* New translations devise.en.yml (Polish)
[ci skip]

* New translations devise.en.yml (Occitan)
[ci skip]

* New translations devise.en.yml (Norwegian)
[ci skip]

* New translations devise.en.yml (Malay)
[ci skip]

* New translations devise.en.yml (Lithuanian)
[ci skip]

* New translations devise.en.yml (Korean)
[ci skip]

* New translations devise.en.yml (Serbian (Cyrillic))
[ci skip]

* New translations devise.en.yml (Kazakh)
[ci skip]

* New translations devise.en.yml (Japanese)
[ci skip]

* New translations devise.en.yml (Italian)
[ci skip]

* New translations devise.en.yml (Indonesian)
[ci skip]

* New translations devise.en.yml (Ido)
[ci skip]

* New translations devise.en.yml (Hungarian)
[ci skip]

* New translations devise.en.yml (Hebrew)
[ci skip]

* New translations devise.en.yml (Greek)
[ci skip]

* New translations devise.en.yml (Russian)
[ci skip]

* New translations devise.en.yml (Serbian (Latin))
[ci skip]

* New translations doorkeeper.en.yml (Chinese Traditional)
[ci skip]

* New translations doorkeeper.en.yml (Albanian)
[ci skip]

* New translations doorkeeper.en.yml (Chinese Simplified)
[ci skip]

* New translations doorkeeper.en.yml (Catalan)
[ci skip]

* New translations doorkeeper.en.yml (Bulgarian)
[ci skip]

* New translations doorkeeper.en.yml (Bengali)
[ci skip]

* New translations doorkeeper.en.yml (Basque)
[ci skip]

* New translations doorkeeper.en.yml (Asturian)
[ci skip]

* New translations doorkeeper.en.yml (Armenian)
[ci skip]

* New translations doorkeeper.en.yml (Arabic)
[ci skip]

* New translations devise.en.yml (Welsh)
[ci skip]

* New translations devise.en.yml (Slovak)
[ci skip]

* New translations devise.en.yml (Ukrainian)
[ci skip]

* New translations devise.en.yml (Turkish)
[ci skip]

* New translations devise.en.yml (Thai)
[ci skip]

* New translations devise.en.yml (Telugu)
[ci skip]

* New translations devise.en.yml (Tamil)
[ci skip]

* New translations devise.en.yml (Swedish)
[ci skip]

* New translations devise.en.yml (Spanish)
[ci skip]

* New translations devise.en.yml (Slovenian)
[ci skip]

* New translations doorkeeper.en.yml (Welsh)
[ci skip]

* i18n-tasks normalize

* yarn manage:translations
2019-06-12 15:56:18 +02:00
Eugen Rochko da33c94c14
Fix Serbian pluralization rules requiring a "many" key (#11061) 2019-06-12 15:53:04 +02:00
Eugen Rochko d13bc8eb6a
Update crowdin.yml 2019-06-12 15:11:00 +02:00
mayaeh 7652190509 i18n: Update Japanese translations (#11035)
* Update Japanese translations

Co-authored-by: Phroneris <phroneris@gmail.com>
Co-authored-by: ruine0213 <ruine@spiele.jp>

* Update Japanese translations
2019-06-12 02:29:48 +02:00
Eugen Rochko 963d7e0377 Update Crowdin configuration file 2019-06-11 22:04:04 +02:00
Eugen Rochko 4913c345b2 Update Crowdin configuration file 2019-06-11 21:49:12 +02:00
Masoud Abkenar 30e2f724ce l10n: update Persian translations (fa.yml) (#11052)
* l10n: update Persian translations (fa.yml)

* Fix fa.yml syntax

* i18n-tasks normalize
2019-06-12 02:55:29 +09:00
Masoud Abkenar 69c2bbcc87 l10n: update Persian translation (#11050)
* l10n: update Persian translation

* Update fa.yml
2019-06-12 00:37:52 +09:00
唐宗勛 02323aa1d8 update zh-CN translations (#11046) 2019-06-11 13:08:40 +09:00
Jeong Arm 40be49fe28 Fix Korean translate (#11047) 2019-06-11 13:06:42 +09:00
Eugen Rochko 92b572e2a3
Fix list not being automatically unpinned when it returns 404 in web UI (#11045) 2019-06-11 02:26:37 +02:00
Eugen Rochko ef438bd7e8
Add German translations (#11043) 2019-06-10 21:36:20 +02:00
ThibG 5bcd98172c Fix clicking on the left side of a conversation not marking it as read (#11041) 2019-06-10 19:27:10 +02:00
ふるふる 62852252dd Fix can't save preference other (#11042) 2019-06-10 19:26:43 +02:00
Eugen Rochko 8514ef723c
Fix login sometimes redirecting to paths that are not pages (#11019)
Fix #11016
2019-06-10 12:28:13 +02:00
mayaeh 210fa3a94e Fix emoji-button appearing above privacy-dropdown (#11027) 2019-06-10 12:27:17 +02:00
Marek Ľach 420551872d Update simple_form.sk.yml (#11028) 2019-06-10 16:25:27 +09:00
manuelviens 0ef55b341d Update simple_form.fr.yml (#11021) 2019-06-10 13:12:51 +09:00
manuelviens fbe879ceaf Update fr.yml (#11023) 2019-06-10 13:12:28 +09:00
manuelviens ce556333ce Update fr.json (#11024) 2019-06-10 13:07:11 +09:00
Marek Ľach 4330629101 Update sk.yml (#11015)
* Update sk.yml

* Update sk.yml

* Update sk.yml

* Update sk.yml

* Update sk.yml

* Update sk.yml
2019-06-09 22:55:37 +02:00
ThibG e428e320b6 Fix old migrations failing because of new version of `strong_migrations` (#11018) 2019-06-09 22:55:28 +02:00
Jeong Arm 654fd071b7 Add missing Korean translations (#11014) 2019-06-09 21:07:50 +02:00
Alix Rossi 9a281bac8d i18n: Update Corsican front-end translation (#11010) 2019-06-09 23:23:30 +09:00
Eugen Rochko 0949c43ab3
Bump version to 2.9.0rc1 (#11004) 2019-06-09 15:53:08 +02:00
Eugen Rochko e5bdfd1640
Run yarn manage:translations (#11008) 2019-06-09 15:52:42 +02:00
Eugen Rochko 8746f4d17b
Change priority of delete activity forwards for replies and reblogs (#11002)
Fix #11001
2019-06-09 12:47:33 +02:00
Eugen Rochko 9add88a920
Fix position of search icon (#11003) 2019-06-09 01:59:42 +02:00
spla 6ecf1825ef i18n: Update Catalan translations (#10998)
* Updated Catalan strings

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update simple_form.ca.yml

* Update simple_form.ca.yml

* Update simple_form.ca.yml

* bundle exec i18n-tasks

* Update ca.json

* Update simple_form.ca.yml

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translation

* i18n Update Catalan translation

* i18n: Update Catalan translations

* i18n: Update Catalan translations
2019-06-09 08:32:22 +09:00
Eugen Rochko 241a8e7b5f
Fix more issues in the light theme (#10996)
* Fix tabs bar in light theme

* Fix borders on small screens in light theme
2019-06-08 22:32:59 +02:00
Darius Kazemi 4431ce52a6 Specify gzip required in tootctl emoji help (#11000) 2019-06-08 12:43:11 -04:00
Aditoo17 537e928186 I18n: Update Czech translation 🇨🇿 (#10995)
* I18n: Update Czech translation

* Fix

* Re-fix

* And also this

* The real fix now (hopefully)
2019-06-08 17:58:40 +02:00
ThibG e9ddd5a159 Put poll options behind content warnings (#10983)
* Put poll options behind CWs in WebUI

* Put polls behind CWs on public pages

* Add poll icon to public pages CWs

* Revert to not showing an icon in the CW button
2019-06-08 17:40:59 +02:00
Eugen Rochko 20dda5cca0
Change full logo to use primary text color of the given theme (#10994)
* Change full logo to use primary text color of the given theme

* Fix colors of public layout header in light theme
2019-06-08 15:30:06 +02:00
Eugen Rochko f4bc77f290
Improve light theme (#10992) 2019-06-08 10:23:41 +02:00
Eugen Rochko 25f93f4097
Fix RTL layout not being RTL within the columns area (#10990) 2019-06-07 23:35:26 +02:00
Eugen Rochko cc8f6b3cda
Fix some React warnings (#10989) 2019-06-07 17:15:18 +02:00
Eugen Rochko 560ec24e58
Change /settings/preferences to redirect to appearance, add /settings/preferences/other (#10988) 2019-06-07 16:51:08 +02:00
ThibG cdb420862e Fix display of alt-text when a media attachment is not available (#10981) 2019-06-07 12:41:08 +02:00
Alix Rossi 62e6a29f0b i18n: Update Corsican translations (#10987) 2019-06-07 19:12:17 +09:00
Eugen Rochko 1db4117030
Change preferences page into appearance, notifications, and other (#10977) 2019-06-07 03:39:24 +02:00
Eugen Rochko a60364ca7d
Add waiting time to list of pending accounts in admin UI (#10985) 2019-06-07 03:24:10 +02:00
Yamagishi Kazutoshi c672676c03 Fix sass-lint config (#10982) 2019-06-06 18:51:46 +02:00
Wenceslao Páez Chávez fe3bf3b0fc Fix overlap of emoji button on search popup (#10978) 2019-06-06 13:40:17 +02:00
Eugen Rochko 5bfd802c57
Fix not being able to directly switch between list timelines in web UI (#10973) 2019-06-06 13:04:49 +02:00
ThibG 2657765d2a Fix “mark as sensitive” not being used in delete & redraft (#10980) 2019-06-06 13:04:34 +02:00
Yamagishi Kazutoshi 70423ce81f require rubocop-rails in .rubocop.yml (#10974)
* Revert "Revert #10957 (rubocop-rails) which is incompatible with CodeClimate (#10965)"

This reverts commit 121d19d7fa.

* Disable Rails/HelperInstanceVariable
2019-06-06 12:31:48 +02:00
Takeshi Umeda c402c291f4 Fix emoji picker being always displayed (#10979)
* Fix emoji picker being always displayed

* Remove duplicate content with other pull-requests
2019-06-06 12:30:14 +02:00
Jeong Arm 8f3c32e29c Scroll to compose form when focus (#10970)
* Scroll to compose form when focus

* Get rid of constructor
2019-06-05 15:29:45 +02:00
ThibG cac9110533 Cleanup various controllers (#10972)
* Remove skip_session! as it is not supported in Rails 5

* Minor cleanup in StreamEntriesController

* Remove redundant mark_cacheable! calls
2019-06-05 14:02:59 +02:00
ThibG 7fa23ec697 Fix potential private status leak (#10969) 2019-06-05 13:40:20 +02:00
ThibG d34a3a2cc7 Fix refreshing featured toots when the new collection is empty (#10971)
Fixes #10945
2019-06-05 13:39:59 +02:00
ThibG 6c464cd424 Do not misattribute inlined boosts if `attributedTo` isn't present (#10967)
* Do not misattribute inlined boosts if `attributedTo` isn't present

Fixes #10950

* Fix tests
2019-06-04 23:24:31 +02:00
Eugen Rochko ed19f33440
Fix margins on profile metadata in single column mode (#10961) 2019-06-04 23:11:57 +02:00
Eugen Rochko 6a9a759f40
Change reblogs counter to be updated when boosted privately (#10964) 2019-06-04 23:11:44 +02:00
Eugen Rochko f2b743e715
Refactor all ActivityPub deliveries to be serialized and signed through one concern (#10966) 2019-06-04 23:11:18 +02:00
Eugen Rochko 48fee1a800
Fix poll API not requiring authentication on non-public polls (#10960)
* Fix poll API not requiring authentication on non-public polls

That API does not reveal the content of the status, i.e. the question
itself, nor who the author is, nor which status it belongs to, but it
does reveal the poll options and how many answers they got

Fix #10959

* Add test
2019-06-04 20:10:26 +02:00
Eugen Rochko 6077eca240
Add profile directory link to single column navigation panel (#10963) 2019-06-04 19:50:38 +02:00
Yamagishi Kazutoshi 121d19d7fa Revert #10957 (rubocop-rails) which is incompatible with CodeClimate (#10965) 2019-06-04 19:35:19 +02:00
Jeong Arm a1e96b2d8a Add missing Korean translations (#10962)
And change some word.
2019-06-04 18:00:09 +02:00
dependabot-preview[bot] 781179b823 Bump intersection-observer from 0.5.1 to 0.7.0 (#10953)
Bumps [intersection-observer](https://github.com/w3c/IntersectionObserver) from 0.5.1 to 0.7.0.
- [Release notes](https://github.com/w3c/IntersectionObserver/releases)
- [Commits](https://github.com/w3c/IntersectionObserver/commits)
2019-06-05 00:56:31 +09:00
Yamagishi Kazutoshi 3e56f95c73 Replace from scss-lint to sass-lint (#10958) 2019-06-04 17:23:18 +02:00
Yamagishi Kazutoshi 3f536f06d6 Use rubocop-rails (#10957) 2019-06-04 15:25:52 +02:00
Yamagishi Kazutoshi da38c0a6b8 Replace from uglifyjs to terser (#10956) 2019-06-04 14:17:09 +02:00
dependabot-preview[bot] 7c682c4825 Bump babel-plugin-react-intl from 3.1.0 to 3.1.3 (#10944)
Bumps [babel-plugin-react-intl](https://github.com/formatjs/babel-plugin-react-intl) from 3.1.0 to 3.1.3.
- [Release notes](https://github.com/formatjs/babel-plugin-react-intl/releases)
- [Commits](https://github.com/formatjs/babel-plugin-react-intl/commits)
2019-06-04 20:52:48 +09:00
dependabot-preview[bot] 07aebe1417 Bump webpacker from 4.0.6 to 4.0.7 (#10948)
Bumps [webpacker](https://github.com/rails/webpacker) from 4.0.6 to 4.0.7.
- [Release notes](https://github.com/rails/webpacker/releases)
- [Changelog](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rails/webpacker/compare/v4.0.6...v4.0.7)
2019-06-04 20:50:06 +09:00
dependabot-preview[bot] c633d65e6f Bump react-swipeable-views from 0.13.0 to 0.13.3 (#10952)
Bumps [react-swipeable-views](https://github.com/oliviertassinari/react-swipeable-views) from 0.13.0 to 0.13.3.
- [Release notes](https://github.com/oliviertassinari/react-swipeable-views/releases)
- [Changelog](https://github.com/oliviertassinari/react-swipeable-views/blob/master/CHANGELOG.md)
- [Commits](https://github.com/oliviertassinari/react-swipeable-views/compare/v0.13.0...v0.13.3)
2019-06-04 20:28:58 +09:00
Eugen Rochko 8265c5e7c8
Change dependabot update schedule from live to weekly (#10949) 2019-06-04 11:23:19 +02:00
dependabot-preview[bot] c11742dd9b Bump fuubar from 2.3.2 to 2.4.0 (#10947)
Bumps [fuubar](https://github.com/thekompanee/fuubar) from 2.3.2 to 2.4.0.
- [Release notes](https://github.com/thekompanee/fuubar/releases)
- [Changelog](https://github.com/thekompanee/fuubar/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thekompanee/fuubar/compare/releases/v2.3.2...releases/v2.4.0)
2019-06-04 14:15:32 +09:00
dependabot-preview[bot] 4e03e50c37 Bump @babel/* from 7.3.4 to 7.4.5 (#10936)
* Bump @babel/plugin-proposal-object-rest-spread from 7.3.4 to 7.4.4

Bumps [@babel/plugin-proposal-object-rest-spread](https://github.com/babel/babel) from 7.3.4 to 7.4.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.3.4...v7.4.4)

* Bump @babel/core from 7.3.4 to 7.4.5

* Bump @babel/plugin-proposal-class-properties from 7.3.4 to 7.4.4

* Bump @babel/plugin-proposal-decorators from 7.3.0 to 7.4.4

* Bump @babel/preset-env from 7.3.4 to 7.4.5

* Bump @babel/runtime from 7.3.4 to 7.4.5
2019-06-04 07:00:35 +09:00
dependabot-preview[bot] 716ea754e7 Bump react from 16.7.0 to 16.8.6 (#10935)
* Bump react from 16.7.0 to 16.8.6

Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) from 16.7.0 to 16.8.6.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v16.8.6/packages/react)

* Bump react-dom from 16.7.0 to 16.8.6

* Bump react-test-renderer from 16.7.0 to 16.8.6
2019-06-04 06:59:54 +09:00
ThibG 3a84bacf86 Handle blank poll options more gracefully (#10946)
Pleroma currently allows (erroneously imho) empty poll options, that is,
options with an empty (but existing) `name`.
2019-06-03 20:04:00 +02:00
dependabot-preview[bot] 8bd2e4403e Bump sass from 1.20.1 to 1.20.3 (#10941)
Bumps [sass](https://github.com/sass/dart-sass) from 1.20.1 to 1.20.3.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.20.1...1.20.3)
2019-06-04 00:46:51 +09:00
dependabot-preview[bot] 8ca93c8654 Bump react-intl from 2.7.2 to 2.9.0 (#10940)
Bumps [react-intl](https://github.com/yahoo/react-intl) from 2.7.2 to 2.9.0.
- [Release notes](https://github.com/yahoo/react-intl/releases)
- [Commits](https://github.com/yahoo/react-intl/compare/v2.7.2...v2.9.0)
2019-06-04 00:14:17 +09:00
dependabot-preview[bot] f2f5c1bd6d Bump offline-plugin from 5.0.6 to 5.0.7 (#10937)
Bumps [offline-plugin](https://github.com/NekR/offline-plugin) from 5.0.6 to 5.0.7.
- [Release notes](https://github.com/NekR/offline-plugin/releases)
- [Changelog](https://github.com/NekR/offline-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NekR/offline-plugin/compare/v5.0.6...v5.0.7)
2019-06-03 21:12:34 +09:00
dependabot-preview[bot] c58cf5c90e Bump babel-jest from 24.5.0 to 24.8.0 (#10938)
Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 24.5.0 to 24.8.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v24.8.0/packages/babel-jest)
2019-06-03 21:12:08 +09:00
Yamagishi Kazutoshi ceddd2ad97 Revert "Bump react-redux-loading-bar from 4.0.8 to 4.2.0 (#10897)" (#10927)
This reverts commit 9ab053a4b4.
2019-06-02 18:22:38 +02:00
ThibG a353dc6030 Fix NotifyService test with regards to reblogs (#10928)
Fixes #10890
2019-06-02 18:08:26 +02:00
Jeong Arm e13e4b28db Fix profile picture preview (#10931) 2019-06-02 18:04:41 +02:00
Takeshi Umeda d93b82af87 Improvement variable height in single column layout (#10917)
* Improvement variable height of compose and navigation panel in single column layout

* Fix wrong quotes and missing commas
2019-06-02 10:05:54 +02:00
dependabot-preview[bot] 2e13f2ac44 Bump eslint-plugin-jsx-a11y from 6.1.2 to 6.2.1 (#10923)
Bumps [eslint-plugin-jsx-a11y](https://github.com/evcohen/eslint-plugin-jsx-a11y) from 6.1.2 to 6.2.1.
- [Release notes](https://github.com/evcohen/eslint-plugin-jsx-a11y/releases)
- [Changelog](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/CHANGELOG.md)
- [Commits](https://github.com/evcohen/eslint-plugin-jsx-a11y/compare/v6.1.2...v6.2.1)
2019-06-02 03:09:53 +09:00
dependabot-preview[bot] 2b8919e448 Bump jest from 24.5.0 to 24.8.0 (#10925)
Bumps [jest](https://github.com/facebook/jest) from 24.5.0 to 24.8.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v24.5.0...v24.8.0)
2019-06-02 03:08:48 +09:00
dependabot-preview[bot] ced51d8878 Bump webpack-dev-server from 3.2.1 to 3.5.1 (#10924)
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 3.2.1 to 3.5.1.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v3.2.1...v3.5.1)
2019-06-02 02:46:11 +09:00
dependabot-preview[bot] 8e34b71c8a Bump eslint-plugin-promise from 4.0.1 to 4.1.1 (#10921)
Bumps [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) from 4.0.1 to 4.1.1.
- [Release notes](https://github.com/xjamundx/eslint-plugin-promise/releases)
- [Changelog](https://github.com/xjamundx/eslint-plugin-promise/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xjamundx/eslint-plugin-promise/commits)
2019-06-02 02:24:54 +09:00
Yamagishi Kazutoshi 2c3c3b2612 Remove dependency on history (#10912) 2019-06-01 09:08:16 +03:00
Hanage999 7c1ca0c37b Center 2-columns layout without side effect (#10915) 2019-06-01 07:59:21 +03:00
Marek Ľach 7f589b66dd Small update for sk.yml (#10913) 2019-06-01 00:33:09 +09:00
dependabot-preview[bot] a77b143aa1 Bump autoprefixer from 9.4.10 to 9.5.1 (#10910)
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 9.4.10 to 9.5.1.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/9.4.10...9.5.1)
2019-05-31 21:33:38 +09:00
dependabot-preview[bot] dc56ea9614 Bump rails-ujs from 5.2.2 to 5.2.3 (#10907)
Bumps [rails-ujs](https://github.com/rails/rails) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/rails/rails/releases)
- [Commits](https://github.com/rails/rails/compare/v5.2.2...v5.2.3)
2019-05-31 20:52:05 +09:00
dependabot-preview[bot] 9b638309d5 Bump sass from 1.17.2 to 1.20.1 (#10908)
Bumps [sass](https://github.com/sass/dart-sass) from 1.17.2 to 1.20.1.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.17.2...1.20.1)
2019-05-31 20:51:16 +09:00
dependabot-preview[bot] fee473beb2 [Security] Bump axios from 0.18.0 to 0.19.0 (#10906)
Bumps [axios](https://github.com/axios/axios) from 0.18.0 to 0.19.0. **This update includes security fixes.**
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.18.0...v0.19.0)
2019-05-31 20:48:59 +09:00
dependabot-preview[bot] 01e5bf8520 Bump webpacker from 4.0.5 to 4.0.6 (#10905)
Bumps [webpacker](https://github.com/rails/webpacker) from 4.0.5 to 4.0.6.
- [Release notes](https://github.com/rails/webpacker/releases)
- [Changelog](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rails/webpacker/compare/v4.0.5...v4.0.6)
2019-05-31 20:44:00 +09:00
dependabot-preview[bot] 81f1db4152 Bump dotenv from 6.2.0 to 8.0.0 (#10888)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 6.2.0 to 8.0.0.
- [Release notes](https://github.com/motdotla/dotenv/releases)
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v6.2.0...v8.0.0)
2019-05-31 12:04:11 +09:00
dependabot-preview[bot] bee0a0582c Bump webpacker from 4.0.4 to 4.0.5 (#10903)
Bumps [webpacker](https://github.com/rails/webpacker) from 4.0.4 to 4.0.5.
- [Release notes](https://github.com/rails/webpacker/releases)
- [Changelog](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rails/webpacker/compare/v4.0.4...v4.0.5)
2019-05-31 07:28:05 +09:00
ThibG 1c78d600d3 Fix old migrations failing because of new version of `strong_migrations` (#10904) 2019-05-30 22:35:29 +03:00
Yamagishi Kazutoshi acc74bed12 Remove dependency on fibers (#10902) 2019-05-30 19:27:19 +03:00
dependabot-preview[bot] 7394652693 Bump webpack-cli from 3.2.3 to 3.3.2 (#10896)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 3.2.3 to 3.3.2.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/V.3.2.3...v3.3.2)
2019-05-30 23:55:25 +09:00
dependabot-preview[bot] 4e32b17aa4 Bump redis from 4.1.1 to 4.1.2 (#10899)
Bumps [redis](https://github.com/redis/redis-rb) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/redis/redis-rb/releases)
- [Changelog](https://github.com/redis/redis-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/redis-rb/compare/v4.1.1...v4.1.2)
2019-05-30 23:50:33 +09:00
dependabot-preview[bot] 5677172d86 Bump rubocop from 0.70.0 to 0.71.0 (#10901)
Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.70.0 to 0.71.0.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.70.0...v0.71.0)
2019-05-30 23:17:54 +09:00
dependabot-preview[bot] 9ab053a4b4 Bump react-redux-loading-bar from 4.0.8 to 4.2.0 (#10897)
Bumps [react-redux-loading-bar](https://github.com/mironov/react-redux-loading-bar) from 4.0.8 to 4.2.0.
- [Release notes](https://github.com/mironov/react-redux-loading-bar/releases)
- [Changelog](https://github.com/mironov/react-redux-loading-bar/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mironov/react-redux-loading-bar/commits)
2019-05-30 21:39:52 +09:00
dependabot-preview[bot] d2af9a9a6d Bump react-select from 2.2.0 to 2.4.4 (#10895)
Bumps [react-select](https://github.com/JedWatson/react-select) from 2.2.0 to 2.4.4.
- [Release notes](https://github.com/JedWatson/react-select/releases)
- [Changelog](https://github.com/JedWatson/react-select/blob/master/.sweet-changelogs.js)
- [Commits](https://github.com/JedWatson/react-select/compare/v2.2.0...v2.4.4)
2019-05-30 20:38:27 +09:00
dependabot-preview[bot] c9e5ce4eba Bump object.values from 1.0.4 to 1.1.0 (#10894)
Bumps [object.values](https://github.com/es-shims/Object.values) from 1.0.4 to 1.1.0.
- [Release notes](https://github.com/es-shims/Object.values/releases)
- [Changelog](https://github.com/es-shims/Object.values/blob/master/CHANGELOG.md)
- [Commits](https://github.com/es-shims/Object.values/compare/v1.0.4...v1.1.0)
2019-05-30 20:37:09 +09:00
Eugen Rochko 738ad9759a
Change default to single column UI (#10847)
Keep current setting for users who were active within the last month
2019-05-30 14:30:38 +03:00
dependabot-preview[bot] dee4f1878d Bump aws-sdk-s3 from 1.40.0 to 1.41.0 (#10892)
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.40.0 to 1.41.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/compare/v1.40.0...v1.41.0)
2019-05-30 12:58:22 +09:00
dependabot-preview[bot] fa48cf96de Bump capybara from 3.21.0 to 3.22.0 (#10893)
Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.21.0 to 3.22.0.
- [Release notes](https://github.com/teamcapybara/capybara/releases)
- [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md)
- [Commits](https://github.com/teamcapybara/capybara/compare/3.21.0...3.22.0)
2019-05-30 09:37:11 +09:00
Eugen Rochko 8d9755e5f5
Change links in right panel to open in the same tab (#10848)
For Rambox compatibility
2019-05-29 17:33:35 +03:00
ThibG 3333250ede Fix React warning about legacy lifecycle calls and sensitive status resetting (#10872) 2019-05-29 17:33:15 +03:00
dependabot-preview[bot] 32fc0777b1 Bump js-yaml from 3.12.0 to 3.13.1 (#10881)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)
2019-05-29 23:17:01 +09:00
dependabot-preview[bot] 1f3bc026f4 Bump express from 4.16.4 to 4.17.1 (#10889)
Bumps [express](https://github.com/expressjs/express) from 4.16.4 to 4.17.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.16.4...4.17.1)
2019-05-29 22:53:20 +09:00
dependabot-preview[bot] c2153c1a76 Bump intl-relativeformat from 2.1.0 to 2.2.0 (#10887)
Bumps [intl-relativeformat](https://github.com/yahoo/intl-relativeformat) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/yahoo/intl-relativeformat/releases)
- [Commits](https://github.com/yahoo/intl-relativeformat/commits)
2019-05-29 22:30:52 +09:00
dependabot-preview[bot] a2c0cf73b6 Bump babel-plugin-react-intl from 3.0.1 to 3.1.0 (#10877)
Bumps [babel-plugin-react-intl](https://github.com/formatjs/babel-plugin-react-intl) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/formatjs/babel-plugin-react-intl/releases)
- [Commits](https://github.com/formatjs/babel-plugin-react-intl/commits)
2019-05-29 19:03:31 +09:00
dependabot-preview[bot] 26e290ae64 Bump strong_migrations from 0.3.1 to 0.4.0 (#10871)
Bumps [strong_migrations](https://github.com/ankane/strong_migrations) from 0.3.1 to 0.4.0.
- [Release notes](https://github.com/ankane/strong_migrations/releases)
- [Changelog](https://github.com/ankane/strong_migrations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ankane/strong_migrations/compare/v0.3.1...v0.4.0)
2019-05-29 18:22:59 +09:00
dependabot-preview[bot] 2c6948bb3f Bump react-redux from 6.0.0 to 6.0.1 (#10879)
Bumps [react-redux](https://github.com/reduxjs/react-redux) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/reduxjs/react-redux/releases)
- [Changelog](https://github.com/reduxjs/react-redux/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reduxjs/react-redux/compare/v6.0.0...v6.0.1)
2019-05-29 18:20:36 +09:00
dependabot-preview[bot] d0a87e4711 Bump @babel/plugin-transform-runtime from 7.3.4 to 7.4.4 (#10878)
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel) from 7.3.4 to 7.4.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.3.4...v7.4.4)
2019-05-29 18:19:16 +09:00
dependabot-preview[bot] bdf4ac1172 Bump webpacker from 4.0.2 to 4.0.4 (#10882)
Bumps [webpacker](https://github.com/rails/webpacker) from 4.0.2 to 4.0.4.
- [Release notes](https://github.com/rails/webpacker/releases)
- [Changelog](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rails/webpacker/compare/v4.0.2...v4.0.4)
2019-05-29 18:16:07 +09:00
dependabot-preview[bot] 60d768d346 Bump rimraf from 2.6.2 to 2.6.3 (#10880)
Bumps [rimraf](https://github.com/isaacs/rimraf) from 2.6.2 to 2.6.3.
- [Release notes](https://github.com/isaacs/rimraf/releases)
- [Commits](https://github.com/isaacs/rimraf/compare/v2.6.2...v2.6.3)
2019-05-29 18:12:53 +09:00
Takeshi Umeda 7f203f7c49 Fix safari post field display issue in single column layout (#10883) 2019-05-29 12:03:56 +03:00
Alix Rossi 33ec9c5095 i18n: Update Corsican front-end translation (#10884) 2019-05-29 17:57:08 +09:00
Yamagishi Kazutoshi 1e5d214d19 Add Dependabot config (#10876) 2019-05-29 09:00:51 +03:00
dependabot-preview[bot] 61ab5b0c83 Bump capybara from 3.20.2 to 3.21.0 (#10854)
Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.20.2 to 3.21.0.
- [Release notes](https://github.com/teamcapybara/capybara/releases)
- [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md)
- [Commits](https://github.com/teamcapybara/capybara/compare/3.20.2...3.21.0)
2019-05-29 11:21:22 +09:00
dependabot-preview[bot] 0b1c7150da Bump tty-prompt from 0.18.1 to 0.19.0 (#10870)
Bumps [tty-prompt](https://github.com/piotrmurach/tty-prompt) from 0.18.1 to 0.19.0.
- [Release notes](https://github.com/piotrmurach/tty-prompt/releases)
- [Changelog](https://github.com/piotrmurach/tty-prompt/blob/master/CHANGELOG.md)
- [Commits](https://github.com/piotrmurach/tty-prompt/compare/v0.18.1...v0.19.0)
2019-05-29 11:10:24 +09:00
mayaeh c6e1229a82 Update Japanese translations. (#10875)
run yarn manage:translations ja && i18n-tasks add-missing ja
2019-05-29 11:09:59 +09:00
Aditoo17 0c2ca1bd38 I18n: Update Czech translation (#10874) 2019-05-29 09:52:41 +09:00
Hinaloe b793722d7d Fix undefined method error (#10868) 2019-05-28 15:31:51 +03:00
dependabot-preview[bot] b1133f1ff9 Bump ox from 2.10.0 to 2.10.1 (#10869)
Bumps [ox](https://github.com/ohler55/ox) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/ohler55/ox/releases)
- [Changelog](https://github.com/ohler55/ox/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ohler55/ox/compare/v2.10.0...v2.10.1)
2019-05-28 20:26:36 +09:00
mayaeh afb17b7045 Fix undefined method error. (#10867) 2019-05-28 05:42:04 +02:00
Alix Rossi e2c0d05538 Update simple_form.co.yml (#10862) 2019-05-28 10:21:30 +09:00
ThibG fe3b863926 Fix web push notifications for polls (#10864)
Fixes #10861
2019-05-28 00:26:08 +02:00
Eugen Rochko 451e5980b6
Refactor footers in web UI into a single component (#10846) 2019-05-27 21:58:41 +02:00
ThibG 0e9b8be18a Improve rate limiting (#10860)
* Rate limit based on remote address IP, not on potential reverse proxy

* Limit rate of unauthenticated API requests further

* Rate-limit paging requests to one every 3 seconds
2019-05-27 21:57:49 +02:00
abcang 3593b85423 Display notifications count on a new single column (#10859) 2019-05-27 21:56:29 +02:00
Eugen Rochko 8d5dcc9301
Use `<use />` to render transparent SVG logo instead of inserting it (#10845) 2019-05-27 03:33:39 +02:00
Takeshi Umeda 3b9c02506d Fix poll visibility on public pages (#10817)
* Fix poll visibility on public pages

* Revert "Fix poll visibility on public pages"

This reverts commit 54a9608add6f855bc6337fe3c65eaee7ba13db49.

* Revert "Change poll options to alphabetic letters when status text is hidden"

This reverts commit c53d67326201b2061990b1874a3547c3647f50d2.
2019-05-26 23:13:29 +02:00
Sandro Jäckel 1e6a1ea075 Docker: Remove dist-upgrade (#10822) 2019-05-26 22:26:45 +02:00
Neil Moore 63483ee543 Create new click handler for status__expand area in status (#10837)
This click handler only activates on left-click, resolving #10798.
This matches behavior in status_content.js, as added in #536
2019-05-26 13:48:45 +02:00
Eugen Rochko 988342a56c
Fix null error in status component when determining showMedia state (#10838)
* Fix null error in status component when determining showMedia state

Also update the showMedia value if the status passed to the
component changes

* Refactor media visibility computation into a defaultMediaVisibility function

* Fix default media visibility with reblogs
2019-05-26 13:48:16 +02:00
Marek Ľach 3d219c5956 Update simple_form.sk.yml (#10842) 2019-05-26 19:26:39 +09:00
Hanage999 4a818ac2de Fix wrong redirect from getting started to home in advanced Web UI (#10839)
* update Ruby to 2.5.3

* Link to Getting Started will not redirect to Home in multi-column UI (https://github.com/tootsuite/mastodon/pull/10835)
2019-05-26 12:22:33 +02:00
Eugen Rochko 0e445ebb13
Improvements to the single column layout (#10835)
* Improvements to the single column layout

- Add follows and followers link to the right panel
- Increase margins around separators in right panel
- Add follow requests link with counter when account is locked to right panel

* Redirect from getting started to home when navigation panel is visible
2019-05-26 02:55:37 +02:00
ThibG a472190729 Add a keyboard shortcut to hide/show media (#10647)
* Move control of media visibility to parent component

* Add keyboard shortcut to toggle media visibility
2019-05-25 23:20:51 +02:00
Sandro Jäckel c90f3b9865 Docker: Keep /var/lib/apt/ to keep apt working (#10830) 2019-05-25 23:20:28 +02:00
Alfie John 0852e643b7 Expand abbreviation to minimise confusion (#10826) 2019-05-25 23:20:18 +02:00
Mélanie Chauvel (ariasuni) 4168aeb234 Avoid cutting bottom of letters of last paragraph of statuses (#10821) 2019-05-25 23:19:39 +02:00
Aditoo17 d55d8a611b I18n: Update Czech translation (#10832) 2019-05-26 05:34:40 +09:00
Eugen Rochko 1e5532e693
Add responsive panels to the single-column layout (#10820)
* Add responsive panels to the single-column layout

* Fixes

* Fix not being able to save the preference

* Fix code style issues

* Set max-height on the compose textarea and add a link to relationship manager
2019-05-25 21:27:00 +02:00
Eugen Rochko 5cdb4c483f
Forward port version bumps to 2.8.3 and 2.8.4 (#10819)
* Bump version to 2.8.3

* Bump version to 2.8.4
2019-05-24 15:57:31 +02:00
ThibG d63c3c0cef Improve streaming server security (#10818)
* Check OAuth token scopes in the streaming API

* Use Sec-WebSocket-Protocol instead of query string to pass WebSocket token

Inspired by https://github.com/kubevirt/kubevirt/issues/1242
2019-05-24 15:21:42 +02:00
Eugen Rochko 84dc21d55d
Various improvements to single column layout (#10809)
- Add potential side panels to single column layout
- Hide FAB on large screens
2019-05-23 20:01:10 +02:00
ThibG 9a5561a5b8 Fix possible race condition when processing statuses (#10815) 2019-05-23 20:00:39 +02:00
ThibG 89d600bedb Move signature verification stoplight to the requests themselves (#10813)
* Move signature verification stoplight to the requests themselves

This avoids blocking messages from known keys for 5 minutes when only one fails…

* Put the stoplight on the actual client IP, not a potential reverse proxy
2019-05-23 15:22:39 +02:00
Yamagishi Kazutoshi 369eb63321 Add sponsor button to GitHub web UI (#10814)
- https://help.github.com/en/articles/displaying-a-sponsor-button-in-your-repository
2019-05-23 15:00:54 +02:00
ThibG 9efcca3c54 Retry ActivityPub inbox delivery on HTTP 401 and 408 errors (#10812)
HTTP 401 responses returned by Mastodon's inbox controller may
be temporary if, for instance, the requesting user's actor/key json
could not be retrieved in a timely fashion. This changes allow retries
instead of dropping the message entirely.

Also added HTTP 408 as that error is by nature temporary.
2019-05-23 15:00:30 +02:00
Eugen Rochko 9ddeb30f90
Add `forceSingleColumn` prop to `<UI />` (#10807)
* Move TabsBar rendering logic from CSS to the ColumnsArea component

* Add forceSingleColumn mode

* Add unread notifications counter to tabs bar

* Add toggle to control `forceSingleColumn`

* Increase paddings in mobile layout responsively at large sizes
2019-05-23 01:35:22 +02:00
abcang ca6c93a2f5 Migrate from uws to cws (#10805) 2019-05-22 18:19:16 +02:00
nzws 8a378d4c3d Fix stacking order of emoji picker (#10801) 2019-05-22 18:00:34 +02:00
dependabot[bot] ce8de3a6e5 Bump aws-sdk-s3 from 1.39.0 to 1.40.0 (#10803)
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.39.0 to 1.40.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/compare/v1.39.0...v1.40.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-22 22:31:05 +09:00
dependabot[bot] bc23de458e Bump rubocop from 0.69.0 to 0.70.0 (#10802)
Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.69.0 to 0.70.0.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.69.0...v0.70.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-22 22:09:10 +09:00
dxwc ee0e68e97a i18n: Complete frontend Bengali translation (#10800)
* i18n: Complete frontend Bengali translation

* run yarn manage:translations
2019-05-22 10:00:58 +09:00
trwnh e3b39ea4a4 Update remote bio test from 160 to 500 (#10799) 2019-05-21 13:29:06 +02:00
Paul Woolcock 0c933c1b8c Add `account_id` param to `GET /api/v1/notifications` (#10796)
* Add `from_account` to notifications API

this adds the ability to filter notifications by the account they
originated from

* passing a non-existent user should cause none to be returned

* Fix codeclimate warnings

* fix more codeclimate warnings

* make requested changes:

* use account id instead of user@domain
* name the param `account_id` instead of `from_account`

* Don't use `return` in a lambda
2019-05-21 13:28:49 +02:00
dependabot[bot] 4d65740663 Bump httplog from 1.2.2 to 1.3.0 (#10795)
Bumps [httplog](https://github.com/trusche/httplog) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/trusche/httplog/releases)
- [Changelog](https://github.com/trusche/httplog/blob/master/CHANGELOG.md)
- [Commits](https://github.com/trusche/httplog/commits/v1.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-21 15:41:15 +09:00
Marek Ľach f261dadefa Update sk.yml (#10788)
* Update sk.yml

* Update sk.yml

* Update sk.yml

* Update sk.yml

* Update sk.yml

* Update sk.yml

* normalize
2019-05-20 15:42:19 +09:00
dependabot[bot] 77e2b68b66 Bump lograge from 0.11.0 to 0.11.1 (#10793)
Bumps [lograge](https://github.com/roidrage/lograge) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/roidrage/lograge/releases)
- [Changelog](https://github.com/roidrage/lograge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/roidrage/lograge/compare/v0.11.0...v0.11.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-20 15:19:56 +09:00
dependabot[bot] ace6bd3570 Bump capybara from 3.20.0 to 3.20.2 (#10794)
Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.20.0 to 3.20.2.
- [Release notes](https://github.com/teamcapybara/capybara/releases)
- [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md)
- [Commits](https://github.com/teamcapybara/capybara/compare/3.20.0...3.20.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-20 15:18:28 +09:00
trwnh a6caf919e2 Change bio limit from 160 to 500 (#10790)
* Change note_length validator from 160 to 500

* Change input maxlength from 160 to 500

* update bio test from 160 to 500

* Multiply a string 30 times instead of 10
2019-05-19 22:51:44 +02:00
ThibG ae18386558 Fix “invited by” not showing up for invited accounts in admin interface (#10791) 2019-05-19 21:40:36 +02:00
Marek Ľach 37a04c329c sk.yml grammar update (#10786)
* sk.yml grammar update

* bundle exec i18n-tasks normalize
2019-05-20 02:27:32 +09:00
Hinaloe bb9d7fad9f fix `isSubmitting` prop case (#10785) 2019-05-19 18:41:41 +02:00
Marek Ľach 692e7cea2a Small corrections for sk translation (#10784) 2019-05-19 22:42:10 +09:00
ThibG 4edf5213dc Add post-deployment migration script to delete public-boosts-of-private-toots (#10783) 2019-05-19 13:49:31 +02:00
Shlee ab829d4aa8 Upgrade redis in docker-compose.yml from 4 to 5 (#9063) 2019-05-19 11:29:26 +02:00
Aditoo17 5ff06af2d2 I18n: Update Czech translation (#10781) 2019-05-19 14:39:16 +09:00
Ben Lubar 2f3e4a64be add og:image:alt for media attachments in embeds (#10779) 2019-05-18 20:57:45 +02:00
Eugen Rochko 6fe474837c
Change poll options to alphabetic letters when status text is hidden (#10685)
Fix #10569
2019-05-18 14:41:16 +02:00
Yusuke Nakamura 2c12620adb Remove 'Weblate' from CONTRIBUTING.md (#10778)
The mastodon project no longer used weblate to translate UI
sentences. (ref #10385)
2019-05-18 14:40:55 +02:00
ThibG a1519a8ef5 Prevent from publicly boosting one's own private toots (#10775) 2019-05-18 00:28:51 +02:00
dependabot[bot] e976a9dfbd Bump aws-sdk-s3 from 1.38.0 to 1.39.0 (#10773)
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.38.0 to 1.39.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/compare/v1.38.0...v1.39.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-17 15:23:21 +09:00
Alix Rossi 520cfde793 i18n: Update Corsican translation (#10770)
* i18n: update Corsican translation

* Fix typo in co.yml
2019-05-17 06:32:46 +02:00
dependabot[bot] 2310dd40fa Bump capybara from 3.19.1 to 3.20.0 (#10768)
Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.19.1 to 3.20.0.
- [Release notes](https://github.com/teamcapybara/capybara/releases)
- [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md)
- [Commits](https://github.com/teamcapybara/capybara/compare/3.19.1...3.20.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-16 16:13:52 +09:00
dependabot[bot] 90093f1795 Bump aws-sdk-s3 from 1.36.1 to 1.38.0 (#10769)
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.36.1 to 1.38.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/compare/v1.36.1...v1.38.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-16 15:00:24 +09:00
manuelviens f4f22391b2 Update simple_form.fr.yml (#10756)
Remplacement des ' par des ’
2019-05-15 14:52:11 +09:00
ThibG c1c8c7b2c8 Minor performance improvements and cleanup in formatter (#10765) 2019-05-15 06:54:06 +02:00
Neil Moore 4ab094d35e Adds click-able div that expands status (#10733) (#10766)
The clickable div is positioned under the account avatar and covers
all empty space below it to the end of the status.
2019-05-15 06:53:23 +02:00
ThibG 14f6ce2885 Record account suspend/silence time and keep track of domain blocks (#10660)
* Record account suspend/silence time and keep track of domain blocks

* Also unblock users who were suspended/silenced before dates were recorded

* Add tests

* Keep track of suspending date for users suspended through the CLI

* Show accurate number of accounts that would be affected by unsuspending an instance

* Change migration to set silenced_at and suspended_at

* Revert "Also unblock users who were suspended/silenced before dates were recorded"

This reverts commit a015c65d2d1e28c7b7cfab8b3f8cd5fb48b8b71c.

* Switch from using suspended and silenced to suspended_at and silenced_at

* Add post-deployment migration script to remove `suspended` and `silenced` columns

* Use Account#silence! and Account#suspend! instead of updating the underlying property

* Add silenced_at and suspended_at migration to post-migration

* Change account fabricator to translate suspended and silenced attributes

* Minor fixes

* Make unblocking domains always retroactive
2019-05-14 19:05:02 +02:00
Marek Ľach 564106c5d6 Update slovak simple_forms (#10763) 2019-05-14 19:55:47 +09:00
dependabot[bot] 76901b65c4 Bump capybara from 3.18.0 to 3.19.1 (#10758)
Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.18.0 to 3.19.1.
- [Release notes](https://github.com/teamcapybara/capybara/releases)
- [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md)
- [Commits](https://github.com/teamcapybara/capybara/compare/3.18.0...3.19.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-14 15:01:47 +09:00
dependabot[bot] 5a24275202 Bump brakeman from 4.5.0 to 4.5.1 (#10757)
Bumps [brakeman](https://github.com/presidentbeef/brakeman) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/presidentbeef/brakeman/releases)
- [Changelog](https://github.com/presidentbeef/brakeman/blob/master/CHANGES.md)
- [Commits](https://github.com/presidentbeef/brakeman/compare/v4.5.0...v4.5.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-14 15:01:22 +09:00
dependabot[bot] d90104204f Bump rubocop from 0.68.1 to 0.69.0 (#10762)
Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.68.1 to 0.69.0.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.68.1...v0.69.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-14 15:00:58 +09:00
nzws 3e15a845c1 Fix some colors in light theme (#10754)
* Fix typo in light theme

* Fix background color of empty column
2019-05-12 05:15:42 +02:00
ThibG dd118449c2 Fix incorrect reference to raw_content (it is raw_text instead) (#10753) 2019-05-11 23:56:07 +02:00
ThibG 6d44f2441b Add toot source to delete result to ease Delete & Redraft (#10669)
* Return Status with raw text in raw_content when deleting a status

* Use raw content if available on delete & redraft

* Rename raw_content to text; do not serialize formatted content when source is requested
2019-05-11 06:46:43 +02:00
nzws be851321c0 Use local time in audit log (#10751) 2019-05-11 06:46:01 +02:00
Alix Rossi 775ee63b71 i18n: Update French translations (#10747)
* Update French JSON

* i18n: Update fr.yml

* i18n: Update simple_form.fr.yml

* Update simple_form.fr.yml

* Update fr.yml
2019-05-10 18:09:46 +02:00
Alix Rossi d25e358f9f i18n: Update Corsican translations (#10746)
* i18n: Update Corsican translations

* Update co.yml

* Fix a translation in co.yml
2019-05-10 18:09:34 +02:00
ThibG 6dc9baad2a Change icon and label depending on whether media is marked as sensitive (#10748)
* Change icon and label depending on whether media is marked as sensitive

* WiP use a checkbox
2019-05-10 17:59:57 +02:00
manuelviens 780d99c204 Update simple_form.fr.yml (#10726)
* Minor modif and add

Modified '' by ’ and added invite_request

* Update simple_form.fr.yml

Modifications suggérées par ThibG

* Update simple_form.fr.yml

Remplacement des ' par des ’.

* Update simple_form.fr.yml

Ajout de deux petits espaces devant sessions:
2019-05-09 23:16:24 +02:00
Marek Ľach 9962174a1f Add strings for Slovak (#10734)
* Add strings for Slovak

* Update sk.yml
2019-05-09 23:16:05 +02:00
manuelviens 9d4e9015a7 Update fr.yml (#10727)
* Update fr.yml

Added missing lines

* Update fr.yml

Application des modifications de ThibG

* Update fr.yml

Modifications proposées par ThibG
2019-05-09 23:15:39 +02:00
Stanislas a3c7dd92f3 Add ES_PREFIX in .env.production.sample (#10087) 2019-05-09 22:41:27 +02:00
Aurélien Reeves fe8a8f779e Add confirm modal for unboosting toots (#10287)
[#3815]

Display the boost modal also when unboosting toots.
2019-05-09 22:39:26 +02:00
ThibG f2be71c293 Add emoji suggestions to CW and poll option fields (#10555)
* Refactor selectComposeSuggestion so that different paths can be updated

* Add suggestions in CW field

* Add emoji suggestion to poll options

* Attempt to fix CSS

* Hide suggestions by default

They will be enabled if the input has focus
2019-05-09 22:10:27 +02:00
ThibG 62f5235b6f Prevent silenced local users from notifying remote users not following them (#10575)
* Prevent silenced local users from notifying remote users not following them

This is an attempt to extend the local restrictions of silenced users to the
federation.

* Add tests

* Add tests for making sure private status don't get sent over OStatus
2019-05-09 22:05:43 +02:00
ThibG 26fc21c188 Add some caching for HTML versions of statuses pages (#10701) 2019-05-09 22:03:44 +02:00
Maciek Baron 0402c52f28 Improve poll link accessibility (#10720)
* Add distinction between hover and active/focus states
* Resolves #10198
2019-05-09 22:03:32 +02:00
Jeong Arm 03801fcaa5 Remove custom emojis on "tootctl domains purge" (#10721)
* Remove custom emojis on domains purge

* Change message "Removing" to "Removed"
2019-05-09 22:03:20 +02:00
Jeong Arm ce8635605c Record deleted(by mod) status to prevent re-appear (#10732)
* Record deleted(by mod) status to prevent re-appear

* Move to Tombstone

* Add missing migration script
2019-05-09 22:03:02 +02:00
Jeong Arm 09eea46631 Bring back crossed eye icon on gallery (#10715) 2019-05-08 18:01:33 +02:00
nzws 5c82d660d1 Fix some colors of high contrast theme (#10711)
* Fix "nothing here" text color of high contrast

* Fix counter border color of high contrast
2019-05-07 23:53:58 +02:00
dependabot[bot] fbff73eccb Bump redis from 4.1.0 to 4.1.1 (#10722)
Bumps [redis](https://github.com/redis/redis-rb) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/redis/redis-rb/releases)
- [Changelog](https://github.com/redis/redis-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/redis-rb/compare/v4.1.0...v4.1.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 14:47:46 +09:00
spla 7562602df8 i18n Update Catalan translation (#10719)
* Updated Catalan strings

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update ca.yml

* Update simple_form.ca.yml

* Update simple_form.ca.yml

* Update simple_form.ca.yml

* bundle exec i18n-tasks

* Update ca.json

* Update simple_form.ca.yml

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translations

* i18n: Update Catalan translation

* i18n Update Catalan translation
2019-05-07 00:55:37 +09:00
dependabot[bot] 7e73a8b8bf Bump parallel_tests from 2.28.0 to 2.29.0 (#10716)
Bumps [parallel_tests](https://github.com/grosser/parallel_tests) from 2.28.0 to 2.29.0.
- [Release notes](https://github.com/grosser/parallel_tests/releases)
- [Commits](https://github.com/grosser/parallel_tests/compare/v2.28.0...v2.29.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-06 15:12:55 +09:00
ThibG b2f5b1045f Add description on hover in media gallery (#10713) 2019-05-06 05:33:56 +02:00
mayaeh 1eb14ef774 i18n: Update Japanese translations (#10706)
* Update Japanese translations.

run yarn manage:translations

This commit includes translations by some users that were done at the transifex.

* Reduce translation text because it becomes two lines.
2019-05-06 04:34:32 +09:00
jeroenpraat e742bff19b 1 NL string update (#10709)
* 1 NL string update

No that weblate isn't used anymore, it would be fine if, or the english strings are update, or there is somewhere an explanation how to generate new strings for a language

* Update nl.json
2019-05-06 04:33:24 +09:00
555 changed files with 14056 additions and 7913 deletions

View File

@ -174,8 +174,7 @@ jobs:
steps:
- *attach_workspace
- run: bundle exec i18n-tasks check-normalized
- run: bundle exec i18n-tasks unused
- run: bundle exec i18n-tasks missing -t plural
- run: bundle exec i18n-tasks unused -l en
- run: bundle exec i18n-tasks check-consistent-interpolations
workflows:

View File

@ -30,8 +30,8 @@ plugins:
channel: eslint-5
rubocop:
enabled: true
channel: rubocop-0-54
scss-lint:
channel: rubocop-0-71
sass-lint:
enabled: true
exclude_patterns:
- spec/

10
.dependabot/config.yml Normal file
View File

@ -0,0 +1,10 @@
version: 1
update_configs:
- package_manager: "ruby:bundler"
directory: "/"
update_schedule: "weekly"
- package_manager: "javascript"
directory: "/"
update_schedule: "weekly"

View File

@ -10,6 +10,7 @@ DB_NAME=postgres
DB_PASS=
DB_PORT=5432
# Optional ElasticSearch configuration
# You may also set ES_PREFIX to share the same cluster between multiple Mastodon servers (falls back to REDIS_NAMESPACE if not set)
# ES_ENABLED=true
# ES_HOST=es
# ES_PORT=9200

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
patreon: mastodon
open_collective: mastodon

View File

@ -1,3 +1,6 @@
require:
- rubocop-rails
AllCops:
TargetRubyVersion: 2.3
Exclude:
@ -82,6 +85,9 @@ Rails/Exit:
- 'lib/mastodon/*'
- 'lib/cli.rb'
Rails/HelperInstanceVariable:
Enabled: false
Style/ClassAndModuleChildren:
Enabled: false

37
.sass-lint.yml Normal file
View File

@ -0,0 +1,37 @@
# Linter Documentation:
# https://github.com/sasstools/sass-lint/tree/v1.13.1/docs/options
files:
include: app/javascript/styles/**/*.scss
ignore:
- app/javascript/styles/mastodon/reset.scss
rules:
# Disallows
no-color-literals: 0
no-css-comments: 0
no-duplicate-properties: 0
no-ids: 0
no-important: 0
no-mergeable-selectors: 0
no-misspelled-properties: 0
no-qualifying-elements: 0
no-transition-all: 0
no-vendor-prefixes: 0
# Nesting
force-element-nesting: 0
force-attribute-nesting: 0
force-pseudo-nesting: 0
# Name Formats
class-name-format: 0
leading-zero: 0
# Style Guide
attribute-quotes: 0
hex-length: 0
indentation: 0
nesting-depth: 0
property-sort-order: 0
quotes: 0

View File

@ -1,264 +0,0 @@
# Linter Documentation:
# https://github.com/brigade/scss-lint/blob/v0.42.2/lib/scss_lint/linter/README.md
scss_files: 'app/javascript/styles/**/*.scss'
exclude:
- app/javascript/styles/reset.scss
linters:
# Reports when you use improper spacing around ! (the "bang") in !default,
# !global, !important, and !optional flags.
BangFormat:
enabled: false
# Whether or not to prefer `border: 0` over `border: none`.
BorderZero:
enabled: false
# Reports when you define a rule set using a selector with chained classes
# (a.k.a. adjoining classes).
ChainedClasses:
enabled: false
# Prefer hexadecimal color codes over color keywords.
# (e.g. `color: green` is a color keyword)
ColorKeyword:
enabled: false
# Prefer color literals (keywords or hexadecimal codes) to be used only in
# variable declarations. They should be referred to via variables everywhere
# else.
ColorVariable:
enabled: true
# Which form of comments to prefer in CSS.
Comment:
enabled: false
# Reports @debug statements (which you probably left behind accidentally).
DebugStatement:
enabled: false
# Rule sets should be ordered as follows:
# - @extend declarations
# - @include declarations without inner @content
# - properties, @include declarations with inner @content
# - nested rule sets.
DeclarationOrder:
enabled: false
# `scss-lint:disable` control comments should be preceded by a comment
# explaining why these linters are being disabled for this file.
# See https://github.com/brigade/scss-lint#disabling-linters-via-source for
# more information.
DisableLinterReason:
enabled: true
# Reports when you define the same property twice in a single rule set.
DuplicateProperty:
enabled: false
# Separate rule, function, and mixin declarations with empty lines.
EmptyLineBetweenBlocks:
enabled: true
# Reports when you have an empty rule set.
EmptyRule:
enabled: true
# Reports when you have an @extend directive.
ExtendDirective:
enabled: false
# Files should always have a final newline. This results in better diffs
# when adding lines to the file, since SCM systems such as git won't
# think that you touched the last line.
FinalNewline:
enabled: false
# HEX colors should use three-character values where possible.
HexLength:
enabled: false
# HEX color values should use lower-case colors to differentiate between
# letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`.
HexNotation:
enabled: true
# Avoid using ID selectors.
IdSelector:
enabled: false
# The basenames of @imported SCSS partials should not begin with an
# underscore and should not include the filename extension.
ImportPath:
enabled: false
# Avoid using !important in properties. It is usually indicative of a
# misunderstanding of CSS specificity and can lead to brittle code.
ImportantRule:
enabled: false
# Indentation should always be done in increments of 2 spaces.
Indentation:
enabled: true
width: 2
# Don't write leading zeros for numeric values with a decimal point.
LeadingZero:
enabled: false
# Reports when you define the same selector twice in a single sheet.
MergeableSelector:
enabled: false
# Functions, mixins, variables, and placeholders should be declared
# with all lowercase letters and hyphens instead of underscores.
NameFormat:
enabled: false
# Avoid nesting selectors too deeply.
NestingDepth:
enabled: false
# Always use placeholder selectors in @extend.
PlaceholderInExtend:
enabled: false
# Sort properties in a strict order.
PropertySortOrder:
enabled: false
# Reports when you use an unknown or disabled CSS property
# (ignoring vendor-prefixed properties).
PropertySpelling:
enabled: false
# Configure which units are allowed for property values.
PropertyUnits:
enabled: false
# Pseudo-elements, like ::before, and ::first-letter, should be declared
# with two colons. Pseudo-classes, like :hover and :first-child, should
# be declared with one colon.
PseudoElement:
enabled: true
# Avoid qualifying elements in selectors (also known as "tag-qualifying").
QualifyingElement:
enabled: false
# Don't write selectors with a depth of applicability greater than 3.
SelectorDepth:
enabled: false
# Selectors should always use hyphenated-lowercase, rather than camelCase or
# snake_case.
SelectorFormat:
enabled: false
convention: hyphenated_lowercase
# Prefer the shortest shorthand form possible for properties that support it.
Shorthand:
enabled: true
# Each property should have its own line, except in the special case of
# single line rulesets.
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: true
# Split selectors onto separate lines after each comma, and have each
# individual selector occupy a single line.
SingleLinePerSelector:
enabled: true
# Commas in lists should be followed by a space.
SpaceAfterComma:
enabled: false
# Properties should be formatted with a single space separating the colon
# from the property's value.
SpaceAfterPropertyColon:
enabled: true
# Properties should be formatted with no space between the name and the
# colon.
SpaceAfterPropertyName:
enabled: true
# Variables should be formatted with a single space separating the colon
# from the variable's value.
SpaceAfterVariableColon:
enabled: true
# Variables should be formatted with no space between the name and the
# colon.
SpaceAfterVariableName:
enabled: false
# Operators should be formatted with a single space on both sides of an
# infix operator.
SpaceAroundOperator:
enabled: true
# Opening braces should be preceded by a single space.
SpaceBeforeBrace:
enabled: true
# Parentheses should not be padded with spaces.
SpaceBetweenParens:
enabled: false
# Enforces that string literals should be written with a consistent form
# of quotes (single or double).
StringQuotes:
enabled: false
# Property values, @extend, @include, and @import directives, and variable
# declarations should always end with a semicolon.
TrailingSemicolon:
enabled: true
# Reports lines containing trailing whitespace.
TrailingWhitespace:
enabled: true
# Don't write trailing zeros for numeric values with a decimal point.
TrailingZero:
enabled: false
# Don't use the `all` keyword to specify transition properties.
TransitionAll:
enabled: false
# Numeric values should not contain unnecessary fractional portions.
UnnecessaryMantissa:
enabled: false
# Do not use parent selector references (&) when they would otherwise
# be unnecessary.
UnnecessaryParentReference:
enabled: false
# URLs should be valid and not contain protocols or domain names.
UrlFormat:
enabled: true
# URLs should always be enclosed within quotes.
UrlQuotes:
enabled: true
# Properties, like color and font, are easier to read and maintain
# when defined using variables rather than literals.
VariableForProperty:
enabled: false
# Avoid vendor prefixes. Or rather: don't write them yourself.
VendorPrefix:
enabled: false
# Omit length units on zero values, e.g. `0px` vs. `0`.
ZeroUnit:
enabled: true

View File

@ -43,4 +43,4 @@ Gruntfile.js
# for specific ignore
!.svgo.yml
!sass-lint/**/*.yml

View File

@ -3,6 +3,132 @@ Changelog
All notable changes to this project will be documented in this file.
## [2.9.2] - 2019-06-22
### Added
- Add `short_description` and `approval_required` to `GET /api/v1/instance` ([Gargron](https://github.com/tootsuite/mastodon/pull/11146))
### Changed
- Change camera icon to paperclip icon in upload form ([koyuawsmbrtn](https://github.com/tootsuite/mastodon/pull/11149))
### Fixed
- Fix audio-only OGG and WebM files not being processed as such ([Gargron](https://github.com/tootsuite/mastodon/pull/11151))
- Fix audio not being downloaded from remote servers ([Gargron](https://github.com/tootsuite/mastodon/pull/11145))
## [2.9.1] - 2019-06-22
### Added
- Add moderation API ([Gargron](https://github.com/tootsuite/mastodon/pull/9387))
- Add audio uploads ([Gargron](https://github.com/tootsuite/mastodon/pull/11123), [Gargron](https://github.com/tootsuite/mastodon/pull/11141))
### Changed
- Change domain blocks to automatically support subdomains ([Gargron](https://github.com/tootsuite/mastodon/pull/11138))
- Change Nanobox configuration to bring it up to date ([danhunsaker](https://github.com/tootsuite/mastodon/pull/11083))
### Removed
- Remove expensive counters from federation page in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11139))
### Fixed
- Fix converted media being saved with original extension and mime type ([Gargron](https://github.com/tootsuite/mastodon/pull/11130))
- Fix layout of identity proofs settings ([acid-chicken](https://github.com/tootsuite/mastodon/pull/11126))
- Fix active scope only returning suspended users ([ThibG](https://github.com/tootsuite/mastodon/pull/11111))
- Fix sanitizer making block level elements unreadable ([Gargron](https://github.com/tootsuite/mastodon/pull/10836))
- Fix label for site theme not being translated in admin UI ([palindromordnilap](https://github.com/tootsuite/mastodon/pull/11121))
- Fix statuses not being filtered irreversibly in web UI under some circumstances ([ThibG](https://github.com/tootsuite/mastodon/pull/11113))
- Fix scrolling behaviour in compose form ([ThibG](https://github.com/tootsuite/mastodon/pull/11093))
## [2.9.0] - 2019-06-13
### Added
- **Add single-column mode in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/10807), [Gargron](https://github.com/tootsuite/mastodon/pull/10848), [Gargron](https://github.com/tootsuite/mastodon/pull/11003), [Gargron](https://github.com/tootsuite/mastodon/pull/10961), [Hanage999](https://github.com/tootsuite/mastodon/pull/10915), [noellabo](https://github.com/tootsuite/mastodon/pull/10917), [abcang](https://github.com/tootsuite/mastodon/pull/10859), [Gargron](https://github.com/tootsuite/mastodon/pull/10820), [Gargron](https://github.com/tootsuite/mastodon/pull/10835), [Gargron](https://github.com/tootsuite/mastodon/pull/10809), [Gargron](https://github.com/tootsuite/mastodon/pull/10963), [noellabo](https://github.com/tootsuite/mastodon/pull/10883), [Hanage999](https://github.com/tootsuite/mastodon/pull/10839))
- Add waiting time to the list of pending accounts in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/10985))
- Add a keyboard shortcut to hide/show media in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10647), [Gargron](https://github.com/tootsuite/mastodon/pull/10838), [ThibG](https://github.com/tootsuite/mastodon/pull/10872))
- Add `account_id` param to `GET /api/v1/notifications` ([pwoolcoc](https://github.com/tootsuite/mastodon/pull/10796))
- Add confirmation modal for unboosting toots in web UI ([aurelien-reeves](https://github.com/tootsuite/mastodon/pull/10287))
- Add emoji suggestions to content warning and poll option fields in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10555))
- Add `source` attribute to response of `DELETE /api/v1/statuses/:id` ([ThibG](https://github.com/tootsuite/mastodon/pull/10669))
- Add some caching for HTML versions of public status pages ([ThibG](https://github.com/tootsuite/mastodon/pull/10701))
- Add button to conveniently copy OAuth code ([ThibG](https://github.com/tootsuite/mastodon/pull/11065))
### Changed
- **Change default layout to single column in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/10847))
- **Change light theme** ([Gargron](https://github.com/tootsuite/mastodon/pull/10992), [Gargron](https://github.com/tootsuite/mastodon/pull/10996), [yuzulabo](https://github.com/tootsuite/mastodon/pull/10754), [Gargron](https://github.com/tootsuite/mastodon/pull/10845))
- **Change preferences page into appearance, notifications, and other** ([Gargron](https://github.com/tootsuite/mastodon/pull/10977), [Gargron](https://github.com/tootsuite/mastodon/pull/10988))
- Change priority of delete activity forwards for replies and reblogs ([Gargron](https://github.com/tootsuite/mastodon/pull/11002))
- Change Mastodon logo to use primary text color of the given theme ([Gargron](https://github.com/tootsuite/mastodon/pull/10994))
- Change reblogs counter to be updated when boosted privately ([Gargron](https://github.com/tootsuite/mastodon/pull/10964))
- Change bio limit from 160 to 500 characters ([trwnh](https://github.com/tootsuite/mastodon/pull/10790))
- Change API rate limiting to reduce allowed unauthenticated requests ([ThibG](https://github.com/tootsuite/mastodon/pull/10860), [hinaloe](https://github.com/tootsuite/mastodon/pull/10868), [mayaeh](https://github.com/tootsuite/mastodon/pull/10867))
- Change help text of `tootctl emoji import` command to specify a gzipped TAR archive is required ([dariusk](https://github.com/tootsuite/mastodon/pull/11000))
- Change web UI to hide poll options behind content warnings ([ThibG](https://github.com/tootsuite/mastodon/pull/10983))
- Change silencing to ensure local effects and remote effects are the same for silenced local users ([ThibG](https://github.com/tootsuite/mastodon/pull/10575))
- Change `tootctl domains purge` to remove custom emoji as well ([Kjwon15](https://github.com/tootsuite/mastodon/pull/10721))
- Change Docker image to keep `apt` working ([SuperSandro2000](https://github.com/tootsuite/mastodon/pull/10830))
### Removed
- Remove `dist-upgrade` from Docker image ([SuperSandro2000](https://github.com/tootsuite/mastodon/pull/10822))
### Fixed
- Fix RTL layout not being RTL within the columns area in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/10990))
- Fix display of alternative text when a media attachment is not available in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10981))
- Fix not being able to directly switch between list timelines in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/10973))
- Fix media sensitivity not being maintained in delete & redraft in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10980))
- Fix emoji picker being always displayed in web UI ([noellabo](https://github.com/tootsuite/mastodon/pull/10979), [yuzulabo](https://github.com/tootsuite/mastodon/pull/10801), [wcpaez](https://github.com/tootsuite/mastodon/pull/10978))
- Fix potential private status leak through caching ([ThibG](https://github.com/tootsuite/mastodon/pull/10969))
- Fix refreshing featured toots when the new collection is empty in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10971))
- Fix undoing domain block also undoing individual moderation on users from before the domain block ([ThibG](https://github.com/tootsuite/mastodon/pull/10660))
- Fix time not being local in the audit log ([yuzulabo](https://github.com/tootsuite/mastodon/pull/10751))
- Fix statuses removed by moderation re-appearing on subsequent fetches ([Kjwon15](https://github.com/tootsuite/mastodon/pull/10732))
- Fix misattribution of inlined announces if `attributedTo` isn't present in ActivityPub ([ThibG](https://github.com/tootsuite/mastodon/pull/10967))
- Fix `GET /api/v1/polls/:id` not requiring authentication for non-public polls ([Gargron](https://github.com/tootsuite/mastodon/pull/10960))
- Fix handling of blank poll options in ActivityPub ([ThibG](https://github.com/tootsuite/mastodon/pull/10946))
- Fix avatar preview aspect ratio on edit profile page ([Kjwon15](https://github.com/tootsuite/mastodon/pull/10931))
- Fix web push notifications not being sent for polls ([ThibG](https://github.com/tootsuite/mastodon/pull/10864))
- Fix cut off letters in last paragraph of statuses in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/10821))
- Fix list not being automatically unpinned when it returns 404 in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11045))
- Fix login sometimes redirecting to paths that are not pages ([Gargron](https://github.com/tootsuite/mastodon/pull/11019))
## [2.8.4] - 2019-05-24
### Fixed
- Fix delivery not retrying on some inbox errors that should be retriable ([ThibG](https://github.com/tootsuite/mastodon/pull/10812))
- Fix unnecessary 5 minute cooldowns on signature verifications in some cases ([ThibG](https://github.com/tootsuite/mastodon/pull/10813))
- Fix possible race condition when processing statuses ([ThibG](https://github.com/tootsuite/mastodon/pull/10815))
### Security
- Require specific OAuth scopes for specific endpoints of the streaming API, instead of merely requiring a token for all endpoints, and allow using WebSockets protocol negotiation to specify the access token instead of using a query string ([ThibG](https://github.com/tootsuite/mastodon/pull/10818))
## [2.8.3] - 2019-05-19
### Added
- Add `og:image:alt` OpenGraph tag ([BenLubar](https://github.com/tootsuite/mastodon/pull/10779))
- Add clickable area below avatar in statuses in web UI ([Dar13](https://github.com/tootsuite/mastodon/pull/10766))
- Add crossed-out eye icon on account gallery in web UI ([Kjwon15](https://github.com/tootsuite/mastodon/pull/10715))
- Add media description tooltip to thumbnails in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10713))
### Changed
- Change "mark as sensitive" button into a checkbox for clarity ([ThibG](https://github.com/tootsuite/mastodon/pull/10748))
### Fixed
- Fix bug allowing users to publicly boost their private statuses ([ThibG](https://github.com/tootsuite/mastodon/pull/10775), [ThibG](https://github.com/tootsuite/mastodon/pull/10783))
- Fix performance in formatter by a little ([ThibG](https://github.com/tootsuite/mastodon/pull/10765))
- Fix some colors in the light theme ([yuzulabo](https://github.com/tootsuite/mastodon/pull/10754))
- Fix some colors of the high contrast theme ([yuzulabo](https://github.com/tootsuite/mastodon/pull/10711))
- Fix ambivalent active state of poll refresh button in web UI ([MaciekBaron](https://github.com/tootsuite/mastodon/pull/10720))
- Fix duplicate posting being possible from web UI ([hinaloe](https://github.com/tootsuite/mastodon/pull/10785))
- Fix "invited by" not showing up in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10791))
## [2.8.2] - 2019-05-05
### Added

View File

@ -18,9 +18,9 @@ Bug reports and feature suggestions can be submitted to [GitHub Issues](https://
## Translations
You can submit translations via [Weblate](https://weblate.joinmastodon.org/). They are periodically merged into the codebase.
You can submit translations via [Crowdin](https://crowdin.com/project/mastodon). They are periodically merged into the codebase.
[![Mastodon translation statistics by language](https://weblate.joinmastodon.org/widgets/mastodon/-/multi-auto.svg)](https://weblate.joinmastodon.org/)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
## Pull requests

View File

@ -7,7 +7,6 @@ SHELL ["bash", "-c"]
ENV NODE_VER="8.15.0"
RUN echo "Etc/UTC" > /etc/localtime && \
apt update && \
apt -y dist-upgrade && \
apt -y install wget make gcc g++ python && \
cd ~ && \
wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER.tar.gz && \
@ -80,13 +79,12 @@ ARG GID=991
RUN apt update && \
echo "Etc/UTC" > /etc/localtime && \
ln -s /opt/jemalloc/lib/* /usr/lib/ && \
apt -y dist-upgrade && \
apt install -y whois wget && \
addgroup --gid $GID mastodon && \
useradd -m -u $UID -g $GID -d /opt/mastodon mastodon && \
echo "mastodon:`head /dev/urandom | tr -dc A-Za-z0-9 | head -c 24 | mkpasswd -s -m sha-256`" | chpasswd
# Install masto runtime deps
# Install mastodon runtime deps
RUN apt -y --no-install-recommends install \
libssl1.1 libpq5 imagemagick ffmpeg \
libicu60 libprotobuf10 libidn11 libyaml-0-2 \
@ -95,7 +93,7 @@ RUN apt -y --no-install-recommends install \
ln -s /opt/mastodon /mastodon && \
gem install bundler && \
rm -rf /var/cache && \
rm -rf /var/lib/apt
rm -rf /var/lib/apt/lists/*
# Add tini
ENV TINI_VERSION="0.18.0"
@ -104,11 +102,11 @@ ADD https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini /tin
RUN echo "$TINI_SUM tini" | sha256sum -c -
RUN chmod +x /tini
# Copy over masto source, and dependencies from building, and set permissions
# Copy over mastodon source, and dependencies from building, and set permissions
COPY --chown=mastodon:mastodon . /opt/mastodon
COPY --from=build-dep --chown=mastodon:mastodon /opt/mastodon /opt/mastodon
# Run masto services in prod mode
# Run mastodon services in prod mode
ENV RAILS_ENV="production"
ENV NODE_ENV="production"

22
Gemfile
View File

@ -15,7 +15,7 @@ gem 'makara', '~> 0.4'
gem 'pghero', '~> 2.2'
gem 'dotenv-rails', '~> 2.7'
gem 'aws-sdk-s3', '~> 1.36', require: false
gem 'aws-sdk-s3', '~> 1.42', require: false
gem 'fog-core', '<= 2.1.0'
gem 'fog-openstack', '~> 0.3', require: false
gem 'paperclip', '~> 6.0'
@ -53,7 +53,7 @@ gem 'htmlentities', '~> 4.3'
gem 'http', '~> 3.3'
gem 'http_accept_language', '~> 2.1'
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2'
gem 'httplog', '~> 1.2'
gem 'httplog', '~> 1.3'
gem 'idn-ruby', require: 'idn'
gem 'kaminari', '~> 1.1'
gem 'link_header', '~> 0.0'
@ -62,7 +62,7 @@ gem 'nokogiri', '~> 1.10'
gem 'nsa', '~> 0.2'
gem 'oj', '~> 3.7'
gem 'ostatus2', '~> 2.0'
gem 'ox', '~> 2.10'
gem 'ox', '~> 2.11'
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
gem 'pundit', '~> 2.0'
gem 'premailer-rails'
@ -82,9 +82,9 @@ gem 'simple-navigation', '~> 4.0'
gem 'simple_form', '~> 4.1'
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
gem 'stoplight', '~> 2.1.3'
gem 'strong_migrations', '~> 0.3'
gem 'strong_migrations', '~> 0.4'
gem 'tty-command', '~> 0.8', require: false
gem 'tty-prompt', '~> 0.18', require: false
gem 'tty-prompt', '~> 0.19', require: false
gem 'twitter-text', '~> 1.14'
gem 'tzinfo-data', '~> 1.2019'
gem 'webpacker', '~> 4.0'
@ -96,7 +96,7 @@ gem 'rdf-normalize', '~> 0.3'
group :development, :test do
gem 'fabrication', '~> 2.20'
gem 'fuubar', '~> 2.3'
gem 'fuubar', '~> 2.4'
gem 'i18n-tasks', '~> 0.9', require: false
gem 'pry-byebug', '~> 3.7'
gem 'pry-rails', '~> 0.3'
@ -108,15 +108,15 @@ group :production, :test do
end
group :test do
gem 'capybara', '~> 3.18'
gem 'capybara', '~> 3.24'
gem 'climate_control', '~> 0.2'
gem 'faker', '~> 1.9'
gem 'microformats', '~> 4.1'
gem 'rails-controller-testing', '~> 1.0'
gem 'rspec-sidekiq', '~> 3.0'
gem 'simplecov', '~> 0.16', require: false
gem 'webmock', '~> 3.5'
gem 'parallel_tests', '~> 2.28'
gem 'webmock', '~> 3.6'
gem 'parallel_tests', '~> 2.29'
end
group :development do
@ -128,10 +128,10 @@ group :development do
gem 'letter_opener', '~> 1.7'
gem 'letter_opener_web', '~> 1.3'
gem 'memory_profiler'
gem 'rubocop', '~> 0.68', require: false
gem 'rubocop', '~> 0.71', require: false
gem 'rubocop-rails', '~> 2.0', require: false
gem 'brakeman', '~> 4.5', require: false
gem 'bundler-audit', '~> 0.6', require: false
gem 'scss_lint', '~> 0.58', require: false
gem 'capistrano', '~> 3.11'
gem 'capistrano-rails', '~> 1.4'

View File

@ -75,20 +75,20 @@ GEM
encryptor (~> 3.0.0)
av (0.9.0)
cocaine (~> 0.5.3)
aws-eventstream (1.0.2)
aws-partitions (1.151.0)
aws-sdk-core (3.48.4)
aws-eventstream (1.0.3)
aws-partitions (1.175.0)
aws-sdk-core (3.55.0)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.17.0)
aws-sdk-core (~> 3, >= 3.48.2)
aws-sdk-kms (1.21.0)
aws-sdk-core (~> 3, >= 3.53.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.36.1)
aws-sdk-core (~> 3, >= 3.48.2)
aws-sdk-s3 (1.42.0)
aws-sdk-core (~> 3, >= 3.53.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.0)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.0)
aws-eventstream (~> 1.0, >= 1.0.2)
bcrypt (3.1.12)
@ -103,7 +103,7 @@ GEM
ffi (~> 1.10.0)
bootsnap (1.4.4)
msgpack (~> 1.0)
brakeman (4.5.0)
brakeman (4.5.1)
browser (2.5.3)
builder (3.2.3)
bullet (6.0.0)
@ -129,13 +129,13 @@ GEM
sshkit (~> 1.3)
capistrano-yarn (2.0.2)
capistrano (~> 3.0)
capybara (3.18.0)
capybara (3.24.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (~> 1.2)
regexp_parser (~> 1.5)
xpath (~> 3.2)
case_transform (0.2)
activesupport
@ -231,7 +231,7 @@ GEM
fugit (1.1.6)
et-orbi (~> 1.1, >= 1.1.6)
raabro (~> 1.1)
fuubar (2.3.2)
fuubar (2.4.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
get_process_mem (0.2.3)
@ -253,7 +253,7 @@ GEM
railties (>= 4.0.1)
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashdiff (0.3.7)
hashdiff (0.4.0)
hashie (3.6.0)
heapy (0.1.4)
highline (2.0.1)
@ -269,7 +269,7 @@ GEM
domain_name (~> 0.5)
http-form_data (2.1.1)
http_accept_language (2.1.1)
httplog (1.2.2)
httplog (1.3.1)
rack (>= 1.0)
rainbow (>= 2.0.0)
i18n (1.6.0)
@ -320,7 +320,7 @@ GEM
letter_opener (~> 1.0)
railties (>= 3.2)
link_header (0.0.8)
lograge (0.11.0)
lograge (0.11.2)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
@ -351,7 +351,7 @@ GEM
msgpack (1.2.10)
multi_json (1.13.1)
multipart-post (2.0.0)
necromancer (0.4.0)
necromancer (0.5.0)
net-ldap (0.16.1)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
@ -382,7 +382,7 @@ GEM
addressable (~> 2.5)
http (~> 3.0)
nokogiri (~> 1.8)
ox (2.10.0)
ox (2.11.0)
paperclip (6.0.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
@ -393,7 +393,7 @@ GEM
av (~> 0.9.0)
paperclip (>= 2.5.2)
parallel (1.17.0)
parallel_tests (2.28.0)
parallel_tests (2.29.0)
parallel
parser (2.6.3.0)
ast (~> 2.4.0)
@ -401,7 +401,7 @@ GEM
equatable (~> 0.5.0)
tty-color (~> 0.4.0)
pg (1.1.4)
pghero (2.2.0)
pghero (2.2.1)
activerecord
pkg-config (1.3.7)
premailer (1.11.1)
@ -420,7 +420,7 @@ GEM
pry (~> 0.10)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (3.0.3)
public_suffix (3.1.0)
puma (3.12.1)
pundit (2.0.1)
activesupport (>= 3.0.0)
@ -470,15 +470,12 @@ GEM
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (12.3.2)
rb-fsevent (0.10.3)
rb-inotify (0.10.0)
ffi (~> 1.0)
rdf (3.0.9)
hamster (~> 3.0)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.3.3)
rdf (>= 2.2, < 4.0)
redis (4.1.0)
redis (4.1.2)
redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3)
@ -497,7 +494,7 @@ GEM
redis-store (>= 1.2, < 2)
redis-store (1.5.0)
redis (>= 2.2, < 5)
regexp_parser (1.4.0)
regexp_parser (1.5.1)
request_store (1.4.1)
rack (>= 1.4)
responders (2.4.1)
@ -527,31 +524,26 @@ GEM
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.8.0)
rubocop (0.68.1)
rubocop (0.71.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
parser (>= 2.6)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.6)
ruby-progressbar (1.10.0)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-rails (2.0.1)
rack (>= 1.1)
rubocop (>= 0.70.0)
ruby-progressbar (1.10.1)
ruby-saml (1.9.0)
nokogiri (>= 1.5.10)
rufus-scheduler (3.5.2)
fugit (~> 1.1, >= 1.1.5)
safe_yaml (1.0.4)
safe_yaml (1.0.5)
sanitize (5.0.0)
crass (~> 1.0.2)
nokogiri (>= 1.8.0)
nokogumbo (~> 2.0)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
scss_lint (0.58.0)
rake (>= 0.9, < 13)
sass (~> 3.5, >= 3.5.5)
sidekiq (5.2.7)
connection_pool (~> 2.2, >= 2.2.2)
rack (>= 1.5.0)
@ -593,8 +585,8 @@ GEM
stoplight (2.1.3)
streamio-ffmpeg (3.0.2)
multi_json (~> 1.8)
strong_migrations (0.3.1)
activerecord (>= 3.2.0)
strong_migrations (0.4.0)
activerecord (>= 5)
temple (0.8.1)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
@ -603,22 +595,19 @@ GEM
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.9)
timers (4.2.0)
tty-color (0.4.3)
tty-command (0.8.2)
pastel (~> 0.7.0)
tty-cursor (0.6.0)
tty-prompt (0.18.1)
necromancer (~> 0.4.0)
tty-cursor (0.7.0)
tty-prompt (0.19.0)
necromancer (~> 0.5.0)
pastel (~> 0.7.0)
timers (~> 4.0)
tty-cursor (~> 0.6.0)
tty-reader (~> 0.5.0)
tty-reader (0.5.0)
tty-cursor (~> 0.6.0)
tty-screen (~> 0.6.4)
tty-reader (~> 0.6.0)
tty-reader (0.6.0)
tty-cursor (~> 0.7)
tty-screen (~> 0.7)
wisper (~> 2.0.0)
tty-screen (0.6.5)
tty-screen (0.7.0)
twitter-text (1.14.7)
unf (~> 0.1.0)
tzinfo (1.2.5)
@ -628,15 +617,15 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.5)
unicode-display_width (1.5.0)
unicode-display_width (1.6.0)
uniform_notifier (1.12.1)
warden (1.2.8)
rack (>= 2.0.6)
webmock (3.5.1)
webmock (3.6.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
webpacker (4.0.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (4.0.7)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
railties (>= 4.2)
@ -658,7 +647,7 @@ DEPENDENCIES
active_record_query_trace (~> 1.6)
addressable (~> 2.6)
annotate (~> 2.7)
aws-sdk-s3 (~> 1.36)
aws-sdk-s3 (~> 1.42)
better_errors (~> 2.5)
binding_of_caller (~> 0.7)
blurhash (~> 0.1)
@ -671,7 +660,7 @@ DEPENDENCIES
capistrano-rails (~> 1.4)
capistrano-rbenv (~> 2.1)
capistrano-yarn (~> 2.0)
capybara (~> 3.18)
capybara (~> 3.24)
charlock_holmes (~> 0.7.6)
chewy (~> 5.0)
cld3 (~> 3.2.4)
@ -689,7 +678,7 @@ DEPENDENCIES
fastimage
fog-core (<= 2.1.0)
fog-openstack (~> 0.3)
fuubar (~> 2.3)
fuubar (~> 2.4)
goldfinger (~> 2.1)
hamlit-rails (~> 0.2)
hiredis (~> 0.6)
@ -697,7 +686,7 @@ DEPENDENCIES
http (~> 3.3)
http_accept_language (~> 2.1)
http_parser.rb (~> 0.6)!
httplog (~> 1.2)
httplog (~> 1.3)
i18n-tasks (~> 0.9)
idn-ruby
iso-639
@ -721,10 +710,10 @@ DEPENDENCIES
omniauth-cas (~> 1.1)
omniauth-saml (~> 1.10)
ostatus2 (~> 2.0)
ox (~> 2.10)
ox (~> 2.11)
paperclip (~> 6.0)
paperclip-av-transcoder (~> 0.6)
parallel_tests (~> 2.28)
parallel_tests (~> 2.29)
pg (~> 1.1)
pghero (~> 2.2)
pkg-config (~> 1.3)
@ -748,9 +737,9 @@ DEPENDENCIES
rqrcode (~> 0.10)
rspec-rails (~> 3.8)
rspec-sidekiq (~> 3.0)
rubocop (~> 0.68)
rubocop (~> 0.71)
rubocop-rails (~> 2.0)
sanitize (~> 5.0)
scss_lint (~> 0.58)
sidekiq (~> 5.2)
sidekiq-bulk (~> 0.2.0)
sidekiq-scheduler (~> 3.0)
@ -762,13 +751,13 @@ DEPENDENCIES
stackprof
stoplight (~> 2.1.3)
streamio-ffmpeg (~> 3.0)
strong_migrations (~> 0.3)
strong_migrations (~> 0.4)
thor (~> 0.20)
tty-command (~> 0.8)
tty-prompt (~> 0.18)
tty-prompt (~> 0.19)
twitter-text (~> 1.14)
tzinfo-data (~> 1.2019)
webmock (~> 3.5)
webmock (~> 3.6)
webpacker (~> 4.0)
webpush

View File

@ -4,13 +4,13 @@
[![GitHub release](https://img.shields.io/github/release/tootsuite/mastodon.svg)][releases]
[![Build Status](https://img.shields.io/circleci/project/github/tootsuite/mastodon.svg)][circleci]
[![Code Climate](https://img.shields.io/codeclimate/maintainability/tootsuite/mastodon.svg)][code_climate]
[![Translation status](https://weblate.joinmastodon.org/widgets/mastodon/-/svg-badge.svg)][weblate]
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
[![Docker Pulls](https://img.shields.io/docker/pulls/tootsuite/mastodon.svg)][docker]
[releases]: https://github.com/tootsuite/mastodon/releases
[circleci]: https://circleci.com/gh/tootsuite/mastodon
[code_climate]: https://codeclimate.com/github/tootsuite/mastodon
[weblate]: https://weblate.joinmastodon.org/engage/mastodon/
[crowdin]: https://crowdin.com/project/mastodon
[docker]: https://hub.docker.com/r/tootsuite/mastodon/
Mastodon is a **free, open-source social network server** based on ActivityPub. Follow friends and discover new ones. Publish anything you want: links, pictures, text, video. All servers of Mastodon are interoperable as a federated network, i.e. users on one server can seamlessly communicate with users from another one. This includes non-Mastodon software that also implements ActivityPub!

View File

@ -46,8 +46,6 @@ class AccountsController < ApplicationController
end
format.json do
mark_cacheable!
render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do
ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)
end

View File

@ -9,8 +9,6 @@ class ActivityPub::CollectionsController < Api::BaseController
before_action :set_cache_headers
def show
skip_session!
render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do
ActiveModelSerializers::SerializableResource.new(
collection_presenter,

View File

@ -10,10 +10,7 @@ class ActivityPub::OutboxesController < Api::BaseController
before_action :set_cache_headers
def show
unless page_requested?
skip_session!
expires_in 1.minute, public: true
end
expires_in 1.minute, public: true unless page_requested?
render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end

View File

@ -48,13 +48,13 @@ module Admin
def approve
authorize @account.user, :approve?
@account.user.approve!
redirect_to admin_accounts_path(pending: '1')
redirect_to admin_pending_accounts_path
end
def reject
authorize @account.user, :reject?
SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)
redirect_to admin_accounts_path(pending: '1')
redirect_to admin_pending_accounts_path
end
def unsilence
@ -127,6 +127,7 @@ module Admin
:by_domain,
:active,
:pending,
:disabled,
:silenced,
:suspended,
:username,

View File

@ -13,7 +13,7 @@ module Admin
authorize :domain_block, :create?
@domain_block = DomainBlock.new(resource_params)
existing_domain_block = resource_params[:domain].present? ? DomainBlock.find_by(domain: resource_params[:domain]) : nil
existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil
if existing_domain_block.present? && !@domain_block.stricter_than?(existing_domain_block)
@domain_block.save
@ -41,7 +41,7 @@ module Admin
def destroy
authorize @domain_block, :destroy?
UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
UnblockDomainService.new.call(@domain_block)
log_action :destroy, @domain_block
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg')
end
@ -53,11 +53,7 @@ module Admin
end
def resource_params
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :retroactive)
end
def retroactive_unblock?
ActiveRecord::Type.lookup(:boolean).cast(resource_params[:retroactive])
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports)
end
end
end

View File

@ -18,7 +18,7 @@ module Admin
@blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count
@available = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url)
@media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size)
@domain_block = DomainBlock.find_by(domain: params[:id])
@domain_block = DomainBlock.rule_for(params[:id])
end
private

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
class Api::V1::Admin::AccountActionsController < Api::BaseController
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:accounts' }
before_action :require_staff!
before_action :set_account
def create
account_action = Admin::AccountAction.new(resource_params)
account_action.target_account = @account
account_action.current_account = current_account
account_action.save!
render_empty
end
private
def set_account
@account = Account.find(params[:account_id])
end
def resource_params
params.permit(
:type,
:report_id,
:warning_preset_id,
:text,
:send_email_notification
)
end
end

View File

@ -0,0 +1,128 @@
# frozen_string_literal: true
class Api::V1::Admin::AccountsController < Api::BaseController
include Authorization
include AccountableConcern
LIMIT = 100
before_action -> { doorkeeper_authorize! :'admin:read', :'admin:read:accounts' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:accounts' }, except: [:index, :show]
before_action :require_staff!
before_action :set_accounts, only: :index
before_action :set_account, except: :index
before_action :require_local_account!, only: [:enable, :approve, :reject]
after_action :insert_pagination_headers, only: :index
FILTER_PARAMS = %i(
local
remote
by_domain
active
pending
disabled
silenced
suspended
username
display_name
email
ip
staff
).freeze
PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze
def index
authorize :account, :index?
render json: @accounts, each_serializer: REST::Admin::AccountSerializer
end
def show
authorize @account, :show?
render json: @account, serializer: REST::Admin::AccountSerializer
end
def enable
authorize @account.user, :enable?
@account.user.enable!
log_action :enable, @account.user
render json: @account, serializer: REST::Admin::AccountSerializer
end
def approve
authorize @account.user, :approve?
@account.user.approve!
render json: @account, serializer: REST::Admin::AccountSerializer
end
def reject
authorize @account.user, :reject?
SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)
render json: @account, serializer: REST::Admin::AccountSerializer
end
def unsilence
authorize @account, :unsilence?
@account.unsilence!
log_action :unsilence, @account
render json: @account, serializer: REST::Admin::AccountSerializer
end
def unsuspend
authorize @account, :unsuspend?
@account.unsuspend!
log_action :unsuspend, @account
render json: @account, serializer: REST::Admin::AccountSerializer
end
private
def set_accounts
@accounts = filtered_accounts.order(id: :desc).includes(user: [:invite_request, :invite]).paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end
def set_account
@account = Account.find(params[:id])
end
def filtered_accounts
AccountFilter.new(filter_params).results
end
def filter_params
params.permit(*FILTER_PARAMS)
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path
api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end
def prev_path
api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty?
end
def pagination_max_id
@accounts.last.id
end
def pagination_since_id
@accounts.first.id
end
def records_continue?
@accounts.size == limit_param(LIMIT)
end
def pagination_params(core_params)
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
end
def require_local_account!
forbidden unless @account.local? && @account.user.present?
end
end

View File

@ -0,0 +1,108 @@
# frozen_string_literal: true
class Api::V1::Admin::ReportsController < Api::BaseController
include Authorization
include AccountableConcern
LIMIT = 100
before_action -> { doorkeeper_authorize! :'admin:read', :'admin:read:reports' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:reports' }, except: [:index, :show]
before_action :require_staff!
before_action :set_reports, only: :index
before_action :set_report, except: :index
after_action :insert_pagination_headers, only: :index
FILTER_PARAMS = %i(
resolved
account_id
target_account_id
).freeze
PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze
def index
authorize :report, :index?
render json: @reports, each_serializer: REST::Admin::ReportSerializer
end
def show
authorize @report, :show?
render json: @report, serializer: REST::Admin::ReportSerializer
end
def assign_to_self
authorize @report, :update?
@report.update!(assigned_account_id: current_account.id)
log_action :assigned_to_self, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end
def unassign
authorize @report, :update?
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end
def reopen
authorize @report, :update?
@report.unresolve!
log_action :reopen, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end
def resolve
authorize @report, :update?
@report.resolve!(current_account)
log_action :resolve, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end
private
def set_reports
@reports = filtered_reports.order(id: :desc).with_accounts.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end
def set_report
@report = Report.find(params[:id])
end
def filtered_reports
ReportFilter.new(filter_params).results
end
def filter_params
params.permit(*FILTER_PARAMS)
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path
api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end
def prev_path
api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty?
end
def pagination_max_id
@reports.last.id
end
def pagination_since_id
@reports.first.id
end
def records_continue?
@reports.size == limit_param(LIMIT)
end
def pagination_params(core_params)
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
end
end

View File

@ -44,7 +44,7 @@ class Api::V1::NotificationsController < Api::BaseController
end
def browserable_account_notifications
current_account.notifications.browserable(exclude_types)
current_account.notifications.browserable(exclude_types, from_account)
end
def target_statuses_from_notifications
@ -81,6 +81,10 @@ class Api::V1::NotificationsController < Api::BaseController
val
end
def from_account
params[:account_id]
end
def pagination_params(core_params)
params.slice(:limit, :exclude_types).permit(:limit, exclude_types: []).merge(core_params)
end

View File

@ -1,13 +1,28 @@
# frozen_string_literal: true
class Api::V1::PollsController < Api::BaseController
include Authorization
before_action -> { authorize_if_got_token! :read, :'read:statuses' }, only: :show
before_action :set_poll
before_action :refresh_poll
respond_to :json
def show
@poll = Poll.attached.find(params[:id])
ActivityPub::FetchRemotePollService.new.call(@poll, current_account) if user_signed_in? && @poll.possibly_stale?
render json: @poll, serializer: REST::PollSerializer, include_results: true
end
private
def set_poll
@poll = Poll.attached.find(params[:id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
raise ActiveRecord::RecordNotFound
end
def refresh_poll
ActivityPub::FetchRemotePollService.new.call(@poll, current_account) if user_signed_in? && @poll.possibly_stale?
end
end

View File

@ -51,6 +51,6 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
def data_params
return {} if params[:data].blank?
params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention])
params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])
end
end

View File

@ -65,7 +65,7 @@ class Api::V1::StatusesController < Api::BaseController
RemovalWorker.perform_async(@status.id)
render_empty
render json: @status, serializer: REST::StatusSerializer, source_requested: true
end
private

View File

@ -22,6 +22,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
favourite: alerts_enabled,
reblog: alerts_enabled,
mention: alerts_enabled,
poll: alerts_enabled,
},
}
@ -57,6 +58,6 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
end
def data_params
@data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention])
@data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])
end
end

View File

@ -152,11 +152,6 @@ class ApplicationController < ActionController::Base
end
def mark_cacheable!
skip_session!
expires_in 0, public: true
end
def skip_session!
request.session_options[:skip] = true
end
end

View File

@ -70,7 +70,6 @@ module AccountControllerConcern
def check_account_suspension
if @account.suspended?
skip_session!
expires_in(3.minutes, public: true)
gone
end

View File

@ -20,7 +20,12 @@ module Localized
if ENV['DEFAULT_LOCALE'].present?
I18n.default_locale
else
request_locale || I18n.default_locale
case request_locale
when /en\b/, nil
I18n.default_locale
else
request_locale
end
end
end

View File

@ -43,13 +43,7 @@ module SignatureVerification
return
end
account_stoplight = Stoplight("source:#{request.ip}") { account_from_key_id(signature_params['keyId']) }
.with_fallback { nil }
.with_threshold(1)
.with_cool_off_time(5.minutes.seconds)
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
account = account_stoplight.run
account = account_from_key_id(signature_params['keyId'])
if account.nil?
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@ -62,13 +56,7 @@ module SignatureVerification
return account unless verify_signature(account, signature, compare_signed_string).nil?
account_stoplight = Stoplight("source:#{request.ip}") { account.possibly_stale? ? account.refresh! : account_refresh_key(account) }
.with_fallback { nil }
.with_threshold(1)
.with_cool_off_time(5.minutes.seconds)
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
account = account_stoplight.run
account = stoplight_wrap_request { account.possibly_stale? ? account.refresh! : account_refresh_key(account) }
if account.nil?
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@ -136,14 +124,23 @@ module SignatureVerification
def account_from_key_id(key_id)
if key_id.start_with?('acct:')
ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, ''))
stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) }
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)
account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false)
account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) }
account
end
end
def stoplight_wrap_request(&block)
Stoplight("source:#{request.remote_ip}", &block)
.with_fallback { nil }
.with_threshold(1)
.with_cool_off_time(5.minutes.seconds)
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
.run
end
def account_refresh_key(account)
return if account.local? || !account.activitypub?
ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true)

View File

@ -1,10 +1,11 @@
# frozen_string_literal: true
class CustomCssController < ApplicationController
skip_before_action :store_current_location
before_action :set_cache_headers
def show
skip_session!
render plain: Setting.custom_css || '', content_type: 'text/css'
end
end

View File

@ -7,8 +7,6 @@ class EmojisController < ApplicationController
def show
respond_to do |format|
format.json do
skip_session!
render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do
ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter)
end

View File

@ -19,10 +19,7 @@ class FollowerAccountsController < ApplicationController
format.json do
raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
if params[:page].blank?
skip_session!
expires_in 3.minutes, public: true
end
expires_in 3.minutes, public: true if params[:page].blank?
render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer,

View File

@ -19,10 +19,7 @@ class FollowingAccountsController < ApplicationController
format.json do
raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
if params[:page].blank?
skip_session!
expires_in 3.minutes, public: true
end
expires_in 3.minutes, public: true if params[:page].blank?
render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer,

View File

@ -58,7 +58,7 @@ class HomeController < ApplicationController
if request.path.start_with?('/web')
new_user_session_path
elsif single_user_mode?
short_account_path(Account.local.where(suspended: false).first)
short_account_path(Account.local.without_suspended.first)
else
about_path
end

View File

@ -1,6 +1,8 @@
# frozen_string_literal: true
class ManifestsController < ApplicationController
skip_before_action :store_current_location
def show
render json: InstancePresenter.new, serializer: ManifestSerializer
end

View File

@ -3,8 +3,12 @@
class MediaController < ApplicationController
include Authorization
skip_before_action :store_current_location
before_action :set_media_attachment
before_action :verify_permitted_status!
before_action :check_playable, only: :player
before_action :allow_iframing, only: :player
content_security_policy only: :player do |p|
p.frame_ancestors(false)
@ -16,8 +20,6 @@ class MediaController < ApplicationController
def player
@body_classes = 'player'
response.headers['X-Frame-Options'] = 'ALLOWALL'
raise ActiveRecord::RecordNotFound unless @media_attachment.video? || @media_attachment.gifv?
end
private
@ -32,4 +34,12 @@ class MediaController < ApplicationController
# Reraise in order to get a 404 instead of a 403 error code
raise ActiveRecord::RecordNotFound
end
def check_playable
not_found unless @media_attachment.larger_media_format?
end
def allow_iframing
response.headers['X-Frame-Options'] = 'ALLOWALL'
end
end

View File

@ -3,6 +3,8 @@
class MediaProxyController < ApplicationController
include RoutingHelper
skip_before_action :store_current_location
def show
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
@ -37,6 +39,6 @@ class MediaProxyController < ApplicationController
end
def reject_media?
DomainBlock.find_by(domain: @media_attachment.account.domain)&.reject_media?
DomainBlock.reject_media?(@media_attachment.account.domain)
end
end

View File

@ -56,8 +56,4 @@ class Settings::IdentityProofsController < Settings::BaseController
def post_params
params.require(:account_identity_proof).permit(:post_status, :status_text)
end
def set_body_classes
@body_classes = ''
end
end

View File

@ -1,32 +0,0 @@
# frozen_string_literal: true
class Settings::NotificationsController < Settings::BaseController
layout 'admin'
before_action :authenticate_user!
def show; end
def update
user_settings.update(user_settings_params.to_h)
if current_user.save
redirect_to settings_notifications_path, notice: I18n.t('generic.changes_saved_msg')
else
render :show
end
end
private
def user_settings
UserSettingsDecorator.new(current_user)
end
def user_settings_params
params.require(:user).permit(
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account),
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class Settings::Preferences::AppearanceController < Settings::PreferencesController
private
def after_update_redirect_path
settings_preferences_appearance_path
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class Settings::Preferences::NotificationsController < Settings::PreferencesController
private
def after_update_redirect_path
settings_preferences_notifications_path
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class Settings::Preferences::OtherController < Settings::PreferencesController
private
def after_update_redirect_path
settings_preferences_other_path
end
end

View File

@ -12,7 +12,7 @@ class Settings::PreferencesController < Settings::BaseController
if current_user.update(user_params)
I18n.locale = current_user.locale
redirect_to settings_preferences_path, notice: I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path, notice: I18n.t('generic.changes_saved_msg')
else
render :show
end
@ -20,6 +20,10 @@ class Settings::PreferencesController < Settings::BaseController
private
def after_update_redirect_path
settings_preferences_path
end
def user_settings
UserSettingsDecorator.new(current_user)
end
@ -49,8 +53,9 @@ class Settings::PreferencesController < Settings::BaseController
:setting_hide_network,
:setting_aggregate_reblogs,
:setting_show_application,
:setting_advanced_layout,
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account),
interactions: %i(must_be_follower must_be_following)
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
end
end

View File

@ -27,7 +27,7 @@ class StatusesController < ApplicationController
def show
respond_to do |format|
format.html do
mark_cacheable! unless user_signed_in?
expires_in 10.seconds, public: true if current_account.nil?
@body_classes = 'with-modals'
@ -38,8 +38,6 @@ class StatusesController < ApplicationController
end
format.json do
mark_cacheable! unless @stream_entry.hidden?
render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)
end
@ -48,8 +46,6 @@ class StatusesController < ApplicationController
end
def activity
skip_session!
render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter)
end
@ -58,7 +54,6 @@ class StatusesController < ApplicationController
def embed
raise ActiveRecord::RecordNotFound if @status.hidden?
skip_session!
expires_in 180, public: true
response.headers['X-Frame-Options'] = 'ALLOWALL'
@autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay])
@ -67,8 +62,6 @@ class StatusesController < ApplicationController
end
def replies
skip_session!
render json: replies_collection_presenter,
serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter,

View File

@ -15,14 +15,13 @@ class StreamEntriesController < ApplicationController
def show
respond_to do |format|
format.html do
redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status'
expires_in 5.minutes, public: true unless @stream_entry.hidden?
redirect_to short_account_status_url(params[:account_username], @stream_entry.activity)
end
format.atom do
unless @stream_entry.hidden?
skip_session!
expires_in 3.minutes, public: true
end
expires_in 3.minutes, public: true unless @stream_entry.hidden?
render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true))
end
@ -50,7 +49,7 @@ class StreamEntriesController < ApplicationController
def set_stream_entry
@stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id])
@type = @stream_entry.activity_type.downcase
@type = 'status'
raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil?
authorize @stream_entry.activity, :show? if @stream_entry.hidden?

View File

@ -3,6 +3,7 @@
module SettingsHelper
HUMAN_LOCALES = {
en: 'English',
'en-CY': 'English (Cybre)',
ar: 'العربية',
ast: 'Asturianu',
bg: 'Български',

View File

@ -16,24 +16,32 @@ module StreamEntriesHelper
if user_signed_in?
if account.id == current_user.account_id
link_to settings_profile_url, class: 'button logo-button' do
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('settings.edit_profile')])
safe_join([svg_logo, t('settings.edit_profile')])
end
elsif current_account.following?(account) || current_account.requested?(account)
link_to account_unfollow_path(account), class: 'button logo-button button--destructive', data: { method: :post } do
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.unfollow')])
safe_join([svg_logo, t('accounts.unfollow')])
end
elsif !(account.memorial? || account.moved?)
link_to account_follow_path(account), class: "button logo-button#{account.blocking?(current_account) ? ' disabled' : ''}", data: { method: :post } do
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.follow')])
safe_join([svg_logo, t('accounts.follow')])
end
end
elsif !(account.memorial? || account.moved?)
link_to account_remote_follow_path(account), class: 'button logo-button modal-button', target: '_new' do
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.follow')])
safe_join([svg_logo, t('accounts.follow')])
end
end
end
def svg_logo
content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo'), 'viewBox' => '0 0 216.4144 232.00976')
end
def svg_logo_full
content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo-full'), 'viewBox' => '0 0 713.35878 175.8678')
end
def account_badge(account, all: false)
if account.bot?
content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles')

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.4144 232.00976"><path d="M107.86523 0C78.203984.2425 49.672422 3.4535937 33.044922 11.089844c0 0-32.97656262 14.752031-32.97656262 65.082031 0 11.525-.224375 25.306175.140625 39.919925 1.19750002 49.22 9.02375002 97.72843 54.53124962 109.77343 20.9825 5.55375 38.99711 6.71547 53.505856 5.91797 26.31125-1.45875 41.08203-9.38867 41.08203-9.38867l-.86914-19.08984s-18.80171 5.92758-39.91796 5.20508c-20.921254-.7175-43.006879-2.25516-46.390629-27.94141-.3125-2.25625-.46875-4.66938-.46875-7.20313 0 0 20.536953 5.0204 46.564449 6.21289 15.915.73001 30.8393-.93343 45.99805-2.74218 29.07-3.47125 54.38125-21.3818 57.5625-37.74805 5.0125-25.78125 4.59961-62.916015 4.59961-62.916015 0-50.33-32.97461-65.082031-32.97461-65.082031C166.80539 3.4535938 138.255.2425 108.59375 0h-.72852zM74.296875 39.326172c12.355 0 21.710234 4.749297 27.896485 14.248047l6.01367 10.080078 6.01563-10.080078c6.185-9.49875 15.54023-14.248047 27.89648-14.248047 10.6775 0 19.28156 3.753672 25.85156 11.076172 6.36875 7.3225 9.53907 17.218828 9.53907 29.673828v60.941408h-24.14454V81.869141c0-12.46875-5.24453-18.798829-15.73828-18.798829-11.6025 0-17.41797 7.508516-17.41797 22.353516v32.375002H96.207031V85.423828c0-14.845-5.815468-22.353515-17.417969-22.353516-10.49375 0-15.740234 6.330079-15.740234 18.798829v59.148439H38.904297V80.076172c0-12.455 3.171016-22.351328 9.541015-29.673828 6.568751-7.3225 15.172813-11.076172 25.851563-11.076172z" fill="#fff"/></svg>
<svg xmlns="http://www.w3.org/2000/svg"><symbol id="mastodon-svg-logo" viewBox="0 0 216.4144 232.00976"><path d="M107.86523 0C78.203984.2425 49.672422 3.4535937 33.044922 11.089844c0 0-32.97656262 14.752031-32.97656262 65.082031 0 11.525-.224375 25.306175.140625 39.919925 1.19750002 49.22 9.02375002 97.72843 54.53124962 109.77343 20.9825 5.55375 38.99711 6.71547 53.505856 5.91797 26.31125-1.45875 41.08203-9.38867 41.08203-9.38867l-.86914-19.08984s-18.80171 5.92758-39.91796 5.20508c-20.921254-.7175-43.006879-2.25516-46.390629-27.94141-.3125-2.25625-.46875-4.66938-.46875-7.20313 0 0 20.536953 5.0204 46.564449 6.21289 15.915.73001 30.8393-.93343 45.99805-2.74218 29.07-3.47125 54.38125-21.3818 57.5625-37.74805 5.0125-25.78125 4.59961-62.916015 4.59961-62.916015 0-50.33-32.97461-65.082031-32.97461-65.082031C166.80539 3.4535938 138.255.2425 108.59375 0h-.72852zM74.296875 39.326172c12.355 0 21.710234 4.749297 27.896485 14.248047l6.01367 10.080078 6.01563-10.080078c6.185-9.49875 15.54023-14.248047 27.89648-14.248047 10.6775 0 19.28156 3.753672 25.85156 11.076172 6.36875 7.3225 9.53907 17.218828 9.53907 29.673828v60.941408h-24.14454V81.869141c0-12.46875-5.24453-18.798829-15.73828-18.798829-11.6025 0-17.41797 7.508516-17.41797 22.353516v32.375002H96.207031V85.423828c0-14.845-5.815468-22.353515-17.417969-22.353516-10.49375 0-15.740234 6.330079-15.740234 18.798829v59.148439H38.904297V80.076172c0-12.455 3.171016-22.351328 9.541015-29.673828 6.568751-7.3225 15.172813-11.076172 25.851563-11.076172z" /></symbol></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -8,6 +8,7 @@ const messages = defineMessages({
export const ALERT_SHOW = 'ALERT_SHOW';
export const ALERT_DISMISS = 'ALERT_DISMISS';
export const ALERT_CLEAR = 'ALERT_CLEAR';
export const ALERT_NOOP = 'ALERT_NOOP';
export function dismissAlert(alert) {
return {
@ -36,7 +37,7 @@ export function showAlertForError(error) {
if (status === 404 || status === 410) {
// Skip these errors as they are reflected in the UI
return {};
return { type: ALERT_NOOP };
}
let message = statusText;

View File

@ -63,6 +63,14 @@ const messages = defineMessages({
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
});
const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1);
export const ensureComposeIsVisible = (getState, routerHistory) => {
if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) {
routerHistory.push('/statuses/new');
}
};
export function changeCompose(text) {
return {
type: COMPOSE_CHANGE,
@ -77,9 +85,7 @@ export function replyCompose(status, routerHistory) {
status: status,
});
if (!getState().getIn(['compose', 'mounted'])) {
routerHistory.push('/statuses/new');
}
ensureComposeIsVisible(getState, routerHistory);
};
};
@ -102,9 +108,7 @@ export function mentionCompose(account, routerHistory) {
account: account,
});
if (!getState().getIn(['compose', 'mounted'])) {
routerHistory.push('/statuses/new');
}
ensureComposeIsVisible(getState, routerHistory);
};
};
@ -115,9 +119,7 @@ export function directCompose(account, routerHistory) {
account: account,
});
if (!getState().getIn(['compose', 'mounted'])) {
routerHistory.push('/statuses/new');
}
ensureComposeIsVisible(getState, routerHistory);
};
};
@ -383,7 +385,7 @@ export function readyComposeSuggestionsAccounts(token, accounts) {
};
};
export function selectComposeSuggestion(position, token, suggestion) {
export function selectComposeSuggestion(position, token, suggestion, path) {
return (dispatch, getState) => {
let completion, startPosition;
@ -405,6 +407,7 @@ export function selectComposeSuggestion(position, token, suggestion) {
position: startPosition,
token,
completion,
path,
});
};
};

View File

@ -48,9 +48,14 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
let filtered = false;
if (notification.type === 'mention') {
const dropRegex = regexFromFilters(filters.filter(filter => filter.get('irreversible')));
const regex = regexFromFilters(filters);
const searchIndex = notification.status.spoiler_text + '\n' + unescapeHTML(notification.status.content);
if (dropRegex && dropRegex.test(searchIndex)) {
return;
}
filtered = regex && regex.test(searchIndex);
}

View File

@ -4,6 +4,7 @@ import { evictStatus } from '../storage/modifier';
import { deleteFromTimelines } from './timelines';
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer';
import { ensureComposeIsVisible } from './compose';
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';
@ -131,14 +132,15 @@ export function fetchStatusFail(id, error, skipLoading) {
};
};
export function redraft(status) {
export function redraft(status, raw_text) {
return {
type: REDRAFT,
status,
raw_text,
};
};
export function deleteStatus(id, router, withRedraft = false) {
export function deleteStatus(id, routerHistory, withRedraft = false) {
return (dispatch, getState) => {
let status = getState().getIn(['statuses', id]);
@ -148,17 +150,14 @@ export function deleteStatus(id, router, withRedraft = false) {
dispatch(deleteStatusRequest(id));
api(getState).delete(`/api/v1/statuses/${id}`).then(() => {
api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
evictStatus(id);
dispatch(deleteStatusSuccess(id));
dispatch(deleteFromTimelines(id));
if (withRedraft) {
dispatch(redraft(status));
if (!getState().getIn(['compose', 'mounted'])) {
router.push('/statuses/new');
}
dispatch(redraft(status, response.data.text));
ensureComposeIsVisible(getState, routerHistory);
}
}).catch(error => {
dispatch(deleteStatusFail(id, error));

View File

@ -0,0 +1,229 @@
import React from 'react';
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
import AutosuggestEmoji from './autosuggest_emoji';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { isRtl } from '../rtl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import classNames from 'classnames';
import { List as ImmutableList } from 'immutable';
const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
let word;
let left = str.slice(0, caretPosition).search(/\S+$/);
let right = str.slice(caretPosition).search(/\s/);
if (right < 0) {
word = str.slice(left);
} else {
word = str.slice(left, right + caretPosition);
}
if (!word || word.trim().length < 3 || searchTokens.indexOf(word[0]) === -1) {
return [null, null];
}
word = word.trim().toLowerCase();
if (word.length > 0) {
return [left + 1, word];
} else {
return [null, null];
}
};
export default class AutosuggestInput extends ImmutablePureComponent {
static propTypes = {
value: PropTypes.string,
suggestions: ImmutablePropTypes.list,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
onSuggestionSelected: PropTypes.func.isRequired,
onSuggestionsClearRequested: PropTypes.func.isRequired,
onSuggestionsFetchRequested: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onKeyUp: PropTypes.func,
onKeyDown: PropTypes.func,
autoFocus: PropTypes.bool,
className: PropTypes.string,
id: PropTypes.string,
searchTokens: PropTypes.arrayOf(PropTypes.string),
maxLength: PropTypes.number,
};
static defaultProps = {
autoFocus: true,
searchTokens: ImmutableList(['@', ':', '#']),
};
state = {
suggestionsHidden: true,
focused: false,
selectedSuggestion: 0,
lastToken: null,
tokenStart: 0,
};
onChange = (e) => {
const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens);
if (token !== null && this.state.lastToken !== token) {
this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
this.props.onSuggestionsFetchRequested(token);
} else if (token === null) {
this.setState({ lastToken: null });
this.props.onSuggestionsClearRequested();
}
this.props.onChange(e);
}
onKeyDown = (e) => {
const { suggestions, disabled } = this.props;
const { selectedSuggestion, suggestionsHidden } = this.state;
if (disabled) {
e.preventDefault();
return;
}
if (e.which === 229 || e.isComposing) {
// Ignore key events during text composition
// e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)
return;
}
switch(e.key) {
case 'Escape':
if (suggestions.size === 0 || suggestionsHidden) {
document.querySelector('.ui').parentElement.focus();
} else {
e.preventDefault();
this.setState({ suggestionsHidden: true });
}
break;
case 'ArrowDown':
if (suggestions.size > 0 && !suggestionsHidden) {
e.preventDefault();
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
}
break;
case 'ArrowUp':
if (suggestions.size > 0 && !suggestionsHidden) {
e.preventDefault();
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
}
break;
case 'Enter':
case 'Tab':
// Select suggestion
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
e.preventDefault();
e.stopPropagation();
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
}
break;
}
if (e.defaultPrevented || !this.props.onKeyDown) {
return;
}
this.props.onKeyDown(e);
}
onBlur = () => {
this.setState({ suggestionsHidden: true, focused: false });
}
onFocus = () => {
this.setState({ focused: true });
}
onSuggestionClick = (e) => {
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));
e.preventDefault();
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
this.input.focus();
}
componentWillReceiveProps (nextProps) {
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
this.setState({ suggestionsHidden: false });
}
}
setInput = (c) => {
this.input = c;
}
renderSuggestion = (suggestion, i) => {
const { selectedSuggestion } = this.state;
let inner, key;
if (typeof suggestion === 'object') {
inner = <AutosuggestEmoji emoji={suggestion} />;
key = suggestion.id;
} else if (suggestion[0] === '#') {
inner = suggestion;
key = suggestion;
} else {
inner = <AutosuggestAccountContainer id={suggestion} />;
key = suggestion;
}
return (
<div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
{inner}
</div>
);
}
render () {
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength } = this.props;
const { suggestionsHidden } = this.state;
const style = { direction: 'ltr' };
if (isRtl(value)) {
style.direction = 'rtl';
}
return (
<div className='autosuggest-input'>
<label>
<span style={{ display: 'none' }}>{placeholder}</span>
<input
type='text'
ref={this.setInput}
disabled={disabled}
placeholder={placeholder}
autoFocus={autoFocus}
value={value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp}
onFocus={this.onFocus}
onBlur={this.onBlur}
style={style}
aria-autocomplete='list'
id={id}
className={className}
maxLength={maxLength}
/>
</label>
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
{suggestions.map(this.renderSuggestion)}
</div>
</div>
);
}
}

View File

@ -55,7 +55,8 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
};
state = {
suggestionsHidden: false,
suggestionsHidden: true,
focused: false,
selectedSuggestion: 0,
lastToken: null,
tokenStart: 0,
@ -134,7 +135,14 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
}
onBlur = () => {
this.setState({ suggestionsHidden: true });
this.setState({ suggestionsHidden: true, focused: false });
}
onFocus = (e) => {
this.setState({ focused: true });
if (this.props.onFocus) {
this.props.onFocus(e);
}
}
onSuggestionClick = (e) => {
@ -145,7 +153,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
}
componentWillReceiveProps (nextProps) {
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
this.setState({ suggestionsHidden: false });
}
}
@ -184,7 +192,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
}
render () {
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus } = this.props;
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, children } = this.props;
const { suggestionsHidden } = this.state;
const style = { direction: 'ltr' };
@ -192,33 +200,39 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
style.direction = 'rtl';
}
return (
<div className='autosuggest-textarea'>
<label>
<span style={{ display: 'none' }}>{placeholder}</span>
return [
<div className='compose-form__autosuggest-wrapper' key='autosuggest-wrapper'>
<div className='autosuggest-textarea'>
<label>
<span style={{ display: 'none' }}>{placeholder}</span>
<Textarea
inputRef={this.setTextarea}
className='autosuggest-textarea__textarea'
disabled={disabled}
placeholder={placeholder}
autoFocus={autoFocus}
value={value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp}
onBlur={this.onBlur}
onPaste={this.onPaste}
style={style}
aria-autocomplete='list'
/>
</label>
<Textarea
inputRef={this.setTextarea}
className='autosuggest-textarea__textarea'
disabled={disabled}
placeholder={placeholder}
autoFocus={autoFocus}
value={value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp}
onFocus={this.onFocus}
onBlur={this.onBlur}
onPaste={this.onPaste}
style={style}
aria-autocomplete='list'
/>
</label>
</div>
{children}
</div>,
<div className='autosuggest-textarea__suggestions-wrapper' key='suggestions-wrapper'>
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
{suggestions.map(this.renderSuggestion)}
</div>
</div>
);
</div>,
];
}
}

View File

@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'mastodon/components/icon';
const formatNumber = num => num > 40 ? '40+' : num;
const IconWithBadge = ({ id, count, className }) => (
<i className='icon-with-badge'>
<Icon id={id} fixedWidth className={className} />
{count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
</i>
);
IconWithBadge.propTypes = {
id: PropTypes.string.isRequired,
count: PropTypes.number.isRequired,
className: PropTypes.string,
};
export default IconWithBadge;

View File

@ -157,7 +157,7 @@ class Item extends React.PureComponent {
if (attachment.get('type') === 'unknown') {
return (
<div className={classNames('media-gallery__item', { standalone })} key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>
<a className='media-gallery__item-thumbnail' href={attachment.get('remote_url')} target='_blank' style={{ cursor: 'pointer' }}>
<a className='media-gallery__item-thumbnail' href={attachment.get('remote_url')} target='_blank' style={{ cursor: 'pointer' }} title={attachment.get('description')}>
<canvas width={32} height={32} ref={this.setCanvasRef} className='media-gallery__preview' />
</a>
</div>
@ -244,6 +244,8 @@ class MediaGallery extends React.PureComponent {
intl: PropTypes.object.isRequired,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
};
static defaultProps = {
@ -251,18 +253,24 @@ class MediaGallery extends React.PureComponent {
};
state = {
visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
width: this.props.defaultWidth,
};
componentWillReceiveProps (nextProps) {
if (!is(nextProps.media, this.props.media)) {
this.setState({ visible: !nextProps.sensitive });
if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
} else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
this.setState({ visible: nextProps.visible });
}
}
handleOpen = () => {
this.setState({ visible: !this.state.visible });
if (this.props.onToggleVisibility) {
this.props.onToggleVisibility();
} else {
this.setState({ visible: !this.state.visible });
}
}
handleClick = (index) => {

View File

@ -65,6 +65,8 @@ const getUnitDelay = units => {
}
};
const fallbackFormat = new Intl.DateTimeFormat('en', shortDateFormatOptions);
export const timeAgoString = (intl, date, now, year) => {
const delta = now - date.getTime();

View File

@ -16,7 +16,7 @@ import { MediaGallery, Video } from '../features/ui/util/async-components';
import { HotKeys } from 'react-hotkeys';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import PollContainer from 'mastodon/containers/poll_container';
import { displayMedia } from '../initial_state';
// We use the component (and not the container) since we do not want
// to use the progress bar to show download progress
@ -39,6 +39,18 @@ export const textForScreenReader = (intl, status, rebloggedByText = false) => {
return values.join(', ');
};
export const defaultMediaVisibility = (status) => {
if (!status) {
return undefined;
}
if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
status = status.get('reblog');
}
return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all');
};
export default @injectIntl
class Status extends ImmutablePureComponent {
@ -85,6 +97,11 @@ class Status extends ImmutablePureComponent {
'hidden',
];
state = {
showMedia: defaultMediaVisibility(this.props.status),
statusId: undefined,
};
// Track height changes we know about to compensate scrolling
componentDidMount () {
this.didShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');
@ -98,11 +115,24 @@ class Status extends ImmutablePureComponent {
}
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) {
return {
showMedia: defaultMediaVisibility(nextProps.status),
statusId: nextProps.status.get('id'),
};
} else {
return null;
}
}
// Compensate height changes
componentDidUpdate (prevProps, prevState, snapshot) {
const doShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');
if (doShowCard && !this.didShowCard) {
this.didShowCard = true;
if (snapshot !== null && this.props.updateScrollBottom) {
if (this.node && this.node.offsetTop < snapshot.top) {
this.props.updateScrollBottom(snapshot.height - snapshot.top);
@ -122,6 +152,10 @@ class Status extends ImmutablePureComponent {
}
}
handleToggleMediaVisibility = () => {
this.setState({ showMedia: !this.state.showMedia });
}
handleClick = () => {
if (this.props.onClick) {
this.props.onClick();
@ -136,6 +170,22 @@ class Status extends ImmutablePureComponent {
this.context.router.history.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`);
}
handleExpandClick = (e) => {
if (this.props.onClick) {
this.props.onClick();
return;
}
if (e.button === 0) {
if (!this.context.router) {
return;
}
const { status } = this.props;
this.context.router.history.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`);
}
}
handleAccountClick = (e) => {
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
const id = e.currentTarget.getAttribute('data-id');
@ -198,6 +248,10 @@ class Status extends ImmutablePureComponent {
this.props.onToggleHidden(this._properStatus());
}
handleHotkeyToggleSensitive = () => {
this.handleToggleMediaVisibility();
}
_properStatus () {
const { status } = this.props;
@ -271,9 +325,7 @@ class Status extends ImmutablePureComponent {
status = status.get('reblog');
}
if (status.get('poll')) {
media = <PollContainer pollId={status.get('poll')} />;
} else if (status.get('media_attachments').size > 0) {
if (status.get('media_attachments').size > 0) {
if (this.props.muted) {
media = (
<AttachmentList
@ -281,23 +333,25 @@ class Status extends ImmutablePureComponent {
media={status.get('media_attachments')}
/>
);
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
const video = status.getIn(['media_attachments', 0]);
} else if (['video', 'audio'].includes(status.getIn(['media_attachments', 0, 'type']))) {
const attachment = status.getIn(['media_attachments', 0]);
media = (
<Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
{Component => (
<Component
preview={video.get('preview_url')}
blurhash={video.get('blurhash')}
src={video.get('url')}
alt={video.get('description')}
preview={attachment.get('preview_url')}
blurhash={attachment.get('blurhash')}
src={attachment.get('url')}
alt={attachment.get('description')}
width={this.props.cachedMediaWidth}
height={110}
inline
sensitive={status.get('sensitive')}
onOpenVideo={this.handleOpenVideo}
cacheWidth={this.props.cacheMediaWidth}
visible={this.state.showMedia}
onToggleVisibility={this.handleToggleMediaVisibility}
/>
)}
</Bundle>
@ -313,6 +367,8 @@ class Status extends ImmutablePureComponent {
onOpenMedia={this.props.onOpenMedia}
cacheWidth={this.props.cacheMediaWidth}
defaultWidth={this.props.cachedMediaWidth}
visible={this.state.showMedia}
onToggleVisibility={this.handleToggleMediaVisibility}
/>
)}
</Bundle>
@ -348,6 +404,7 @@ class Status extends ImmutablePureComponent {
moveUp: this.handleHotkeyMoveUp,
moveDown: this.handleHotkeyMoveDown,
toggleHidden: this.handleHotkeyToggleHidden,
toggleSensitive: this.handleHotkeyToggleSensitive,
};
return (
@ -356,6 +413,7 @@ class Status extends ImmutablePureComponent {
{prepend}
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
<div className='status__expand' onClick={this.handleExpandClick} role='presentation' />
<div className='status__info'>
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>

View File

@ -5,6 +5,7 @@ import { isRtl } from '../rtl';
import { FormattedMessage } from 'react-intl';
import Permalink from './permalink';
import classnames from 'classnames';
import PollContainer from 'mastodon/containers/poll_container';
import Icon from 'mastodon/components/icon';
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
@ -106,8 +107,12 @@ export default class StatusContent extends React.PureComponent {
const [ startX, startY ] = this.startXY;
const [ deltaX, deltaY ] = [Math.abs(e.clientX - startX), Math.abs(e.clientY - startY)];
if (e.target.localName === 'button' || e.target.localName === 'a' || (e.target.parentNode && (e.target.parentNode.localName === 'button' || e.target.parentNode.localName === 'a'))) {
return;
let element = e.target;
while (element) {
if (element.localName === 'button' || element.localName === 'a' || element.localName === 'label') {
return;
}
element = element.parentNode;
}
if (deltaX + deltaY < 5 && e.button === 0 && this.props.onClick) {
@ -191,6 +196,8 @@ export default class StatusContent extends React.PureComponent {
{mentionsPlaceholder}
<div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} style={directionStyle} dangerouslySetInnerHTML={content} lang={status.get('language')} />
{!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} />}
</div>
);
} else if (this.props.onClick) {
@ -212,9 +219,13 @@ export default class StatusContent extends React.PureComponent {
output.push(readMoreButton);
}
if (status.get('poll')) {
output.push(<PollContainer pollId={status.get('poll')} />);
}
return output;
} else {
return (
const output = [
<div
tabIndex='0'
ref={this.setRef}
@ -222,8 +233,14 @@ export default class StatusContent extends React.PureComponent {
style={directionStyle}
dangerouslySetInnerHTML={content}
lang={status.get('language')}
/>
);
/>,
];
if (status.get('poll')) {
output.push(<PollContainer pollId={status.get('poll')} />);
}
return output;
}
}

View File

@ -69,18 +69,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
onModalReblog (status) {
dispatch(reblog(status));
},
onReblog (status, e) {
if (status.get('reblogged')) {
dispatch(unreblog(status));
} else {
if (e.shiftKey || !boostModal) {
this.onModalReblog(status);
} else {
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
}
dispatch(reblog(status));
}
},
onReblog (status, e) {
if (e.shiftKey || !boostModal) {
this.onModalReblog(status);
} else {
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
}
},

View File

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Icon from 'mastodon/components/icon';
import { autoPlayGif, displayMedia } from 'mastodon/initial_state';
import classNames from 'classnames';
import { decode } from 'blurhash';
@ -88,8 +89,10 @@ export default class MediaItem extends ImmutablePureComponent {
const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`;
const height = width;
const status = attachment.get('status');
const title = status.get('spoiler_text') || attachment.get('description');
let thumbnail = '';
let icon;
if (attachment.get('type') === 'unknown') {
// Skip
@ -131,11 +134,20 @@ export default class MediaItem extends ImmutablePureComponent {
);
}
if (!visible) {
icon = (
<span className='account-gallery__item__icons'>
<Icon id='eye-slash' />
</span>
);
}
return (
<div className='account-gallery__item' style={{ width, height }}>
<a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick}>
<a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick} title={title}>
<canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })} />
{visible && thumbnail}
{!visible && icon}
</a>
</div>
);

View File

@ -46,7 +46,7 @@ class ActionBar extends React.PureComponent {
return (
<div className='compose__action-bar'>
<div className='compose__action-bar-dropdown'>
<DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' />
<DropdownMenuContainer items={menu} icon='chevron-down' size={16} direction='right' />
</div>
</div>
);

View File

@ -5,6 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
import AutosuggestInput from '../../../components/autosuggest_input';
import PollButtonContainer from '../containers/poll_button_container';
import UploadButtonContainer from '../containers/upload_button_container';
import { defineMessages, injectIntl } from 'react-intl';
@ -59,6 +60,7 @@ class ComposeForm extends ImmutablePureComponent {
onPickEmoji: PropTypes.func.isRequired,
showSearch: PropTypes.bool,
anyMedia: PropTypes.bool,
singleColumn: PropTypes.bool,
};
static defaultProps = {
@ -102,13 +104,23 @@ class ComposeForm extends ImmutablePureComponent {
}
onSuggestionSelected = (tokenStart, token, value) => {
this.props.onSuggestionSelected(tokenStart, token, value);
this.props.onSuggestionSelected(tokenStart, token, value, ['text']);
}
onSpoilerSuggestionSelected = (tokenStart, token, value) => {
this.props.onSuggestionSelected(tokenStart, token, value, ['spoiler_text']);
}
handleChangeSpoilerText = (e) => {
this.props.onChangeSpoilerText(e.target.value);
}
handleFocus = () => {
if (this.composeForm && !this.props.singleColumn) {
this.composeForm.scrollIntoView();
}
}
componentDidUpdate (prevProps) {
// This statement does several things:
// - If we're beginning a reply, and,
@ -135,7 +147,7 @@ class ComposeForm extends ImmutablePureComponent {
this.autosuggestTextarea.textarea.focus();
} else if (this.props.spoiler !== prevProps.spoiler) {
if (this.props.spoiler) {
this.spoilerText.focus();
this.spoilerText.input.focus();
} else {
this.autosuggestTextarea.textarea.focus();
}
@ -150,6 +162,10 @@ class ComposeForm extends ImmutablePureComponent {
this.spoilerText = c;
}
setRef = c => {
this.composeForm = c;
};
handleEmojiPick = (data) => {
const { text } = this.props;
const position = this.autosuggestTextarea.textarea.selectionStart;
@ -172,41 +188,50 @@ class ComposeForm extends ImmutablePureComponent {
}
return (
<div className='compose-form'>
<div className='compose-form' ref={this.setRef}>
<WarningContainer />
<ReplyIndicatorContainer />
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
<label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.spoiler_placeholder)}</span>
<input placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={this.props.spoilerText} onChange={this.handleChangeSpoilerText} onKeyDown={this.handleKeyDown} tabIndex={this.props.spoiler ? 0 : -1} type='text' className='spoiler-input__input' id='cw-spoiler-input' ref={this.setSpoilerText} />
</label>
</div>
<div className='compose-form__autosuggest-wrapper'>
<AutosuggestTextarea
ref={this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.placeholder)}
disabled={disabled}
value={this.props.text}
onChange={this.handleChange}
suggestions={this.props.suggestions}
<AutosuggestInput
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
value={this.props.spoilerText}
onChange={this.handleChangeSpoilerText}
onKeyDown={this.handleKeyDown}
disabled={!this.props.spoiler}
ref={this.setSpoilerText}
suggestions={this.props.suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
onSuggestionSelected={this.onSuggestionSelected}
onPaste={onPaste}
autoFocus={!showSearch && !isMobile(window.innerWidth)}
onSuggestionSelected={this.onSpoilerSuggestionSelected}
searchTokens={[':']}
id='cw-spoiler-input'
className='spoiler-input__input'
/>
</div>
<AutosuggestTextarea
ref={this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.placeholder)}
disabled={disabled}
value={this.props.text}
onChange={this.handleChange}
suggestions={this.props.suggestions}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
onSuggestionSelected={this.onSuggestionSelected}
onPaste={onPaste}
autoFocus={!showSearch && !isMobile(window.innerWidth)}
>
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
</div>
<div className='compose-form__modifiers'>
<UploadFormContainer />
<PollFormContainer />
</div>
<div className='compose-form__modifiers'>
<UploadFormContainer />
<PollFormContainer />
</div>
</AutosuggestTextarea>
<div className='compose-form__buttons-wrapper'>
<div className='compose-form__buttons'>

View File

@ -20,7 +20,7 @@ export default class NavigationBar extends ImmutablePureComponent {
<div className='navigation-bar'>
<Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`}>
<span style={{ display: 'none' }}>{this.props.account.get('acct')}</span>
<Avatar account={this.props.account} size={40} />
<Avatar account={this.props.account} size={48} />
</Permalink>
<div className='navigation-bar__profile'>

View File

@ -5,6 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import Icon from 'mastodon/components/icon';
import AutosuggestInput from 'mastodon/components/autosuggest_input';
import classNames from 'classnames';
const messages = defineMessages({
@ -27,6 +28,10 @@ class Option extends React.PureComponent {
onChange: PropTypes.func.isRequired,
onRemove: PropTypes.func.isRequired,
onToggleMultiple: PropTypes.func.isRequired,
suggestions: ImmutablePropTypes.list,
onClearSuggestions: PropTypes.func.isRequired,
onFetchSuggestions: PropTypes.func.isRequired,
onSuggestionSelected: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
@ -38,12 +43,25 @@ class Option extends React.PureComponent {
this.props.onRemove(this.props.index);
};
handleToggleMultiple = e => {
this.props.onToggleMultiple();
e.preventDefault();
e.stopPropagation();
};
onSuggestionsClearRequested = () => {
this.props.onClearSuggestions();
}
onSuggestionsFetchRequested = (token) => {
this.props.onFetchSuggestions(token);
}
onSuggestionSelected = (tokenStart, token, value) => {
this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]);
}
render () {
const { isPollMultiple, title, index, intl } = this.props;
@ -57,12 +75,16 @@ class Option extends React.PureComponent {
tabIndex='0'
/>
<input
type='text'
<AutosuggestInput
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
maxLength={25}
value={title}
onChange={this.handleOptionTitleChange}
suggestions={this.props.suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
onSuggestionSelected={this.onSuggestionSelected}
searchTokens={[':']}
/>
</label>
@ -87,6 +109,10 @@ class PollForm extends ImmutablePureComponent {
onAddOption: PropTypes.func.isRequired,
onRemoveOption: PropTypes.func.isRequired,
onChangeSettings: PropTypes.func.isRequired,
suggestions: ImmutablePropTypes.list,
onClearSuggestions: PropTypes.func.isRequired,
onFetchSuggestions: PropTypes.func.isRequired,
onSuggestionSelected: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
@ -103,7 +129,7 @@ class PollForm extends ImmutablePureComponent {
};
render () {
const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl } = this.props;
const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl, ...other } = this.props;
if (!options) {
return null;
@ -112,7 +138,7 @@ class PollForm extends ImmutablePureComponent {
return (
<div className='compose-form__poll-wrapper'>
<ul>
{options.map((title, i) => <Option title={title} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} />)}
{options.map((title, i) => <Option title={title} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} {...other} />)}
</ul>
<div className='poll__footer'>

View File

@ -129,7 +129,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
// It should not be transformed when mounting because the resulting
// size will be used to determine the coordinate of the menu by
// react-overlays
<div className={`privacy-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} role='listbox' ref={this.setRef}>
<div className={`privacy-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null, zIndex: 2 }} role='listbox' ref={this.setRef}>
{items.map(item => (
<div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
<div className='privacy-dropdown__option__icon'>

View File

@ -7,6 +7,7 @@ import DisplayName from '../../../components/display_name';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { isRtl } from '../../../rtl';
import AttachmentList from 'mastodon/components/attachment_list';
const messages = defineMessages({
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
@ -60,6 +61,13 @@ class ReplyIndicator extends ImmutablePureComponent {
</div>
<div className='reply-indicator__content' style={style} dangerouslySetInnerHTML={content} />
{status.get('media_attachments').size > 0 && (
<AttachmentList
compact
media={status.get('media_attachments')}
/>
)}
</div>
);
}

View File

@ -21,7 +21,7 @@ class SearchPopout extends React.PureComponent {
const { style } = this.props;
const extraInformation = searchEnabled ? <FormattedMessage id='search_popout.tips.full_text' defaultMessage='Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' /> : <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' />;
return (
<div style={{ ...style, position: 'absolute', width: 285 }}>
<div style={{ ...style, position: 'absolute', width: 285, zIndex: 2 }}>
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
{({ opacity, scaleX, scaleY }) => (
<div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
@ -47,6 +47,10 @@ class SearchPopout extends React.PureComponent {
export default @injectIntl
class Search extends React.PureComponent {
static contextTypes = {
router: PropTypes.object.isRequired,
};
static propTypes = {
value: PropTypes.string.isRequired,
submitted: PropTypes.bool,
@ -54,6 +58,7 @@ class Search extends React.PureComponent {
onSubmit: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired,
onShow: PropTypes.func.isRequired,
openInRoute: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
@ -76,7 +81,12 @@ class Search extends React.PureComponent {
handleKeyUp = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.props.onSubmit();
if (this.props.openInRoute) {
this.context.router.history.push('/search');
}
} else if (e.key === 'Escape') {
document.querySelector('.ui').parentElement.focus();
}

View File

@ -7,9 +7,11 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
const messages = defineMessages({
upload: { id: 'upload_button.label', defaultMessage: 'Add media (JPEG, PNG, GIF, WebM, MP4, MOV)' },
upload: { id: 'upload_button.label', defaultMessage: 'Add media ({formats})' },
});
const SUPPORTED_FORMATS = 'JPEG, PNG, GIF, WebM, MP4, MOV, OGG, WAV, MP3, FLAC';
const makeMapStateToProps = () => {
const mapStateToProps = state => ({
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
@ -60,9 +62,9 @@ class UploadButton extends ImmutablePureComponent {
return (
<div className='compose-form__upload-button'>
<IconButton icon='camera' title={intl.formatMessage(messages.upload)} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
<IconButton icon='paperclip' title={intl.formatMessage(messages.upload, { formats: SUPPORTED_FORMATS })} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
<label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.upload)}</span>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.upload, { formats: SUPPORTED_FORMATS })}</span>
<input
key={resetFileKey}
ref={this.setRef}

View File

@ -20,7 +20,7 @@ const mapStateToProps = state => ({
focusDate: state.getIn(['compose', 'focusDate']),
caretPosition: state.getIn(['compose', 'caretPosition']),
preselectDate: state.getIn(['compose', 'preselectDate']),
is_submitting: state.getIn(['compose', 'is_submitting']),
isSubmitting: state.getIn(['compose', 'is_submitting']),
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
isUploading: state.getIn(['compose', 'is_uploading']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
@ -45,8 +45,8 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(fetchComposeSuggestions(token));
},
onSuggestionSelected (position, token, suggestion) {
dispatch(selectComposeSuggestion(position, token, suggestion));
onSuggestionSelected (position, token, suggestion, path) {
dispatch(selectComposeSuggestion(position, token, suggestion, path));
},
onChangeSpoilerText (checked) {

View File

@ -1,8 +1,14 @@
import { connect } from 'react-redux';
import PollForm from '../components/poll_form';
import { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose';
import {
clearComposeSuggestions,
fetchComposeSuggestions,
selectComposeSuggestion,
} from '../../../actions/compose';
const mapStateToProps = state => ({
suggestions: state.getIn(['compose', 'suggestions']),
options: state.getIn(['compose', 'poll', 'options']),
expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
isMultiple: state.getIn(['compose', 'poll', 'multiple']),
@ -24,6 +30,19 @@ const mapDispatchToProps = dispatch => ({
onChangeSettings(expiresIn, isMultiple) {
dispatch(changePollSettings(expiresIn, isMultiple));
},
onClearSuggestions () {
dispatch(clearComposeSuggestions());
},
onFetchSuggestions (token) {
dispatch(fetchComposeSuggestions(token));
},
onSuggestionSelected (position, token, accountId, path) {
dispatch(selectComposeSuggestion(position, token, accountId, path));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(PollForm);

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import { changeComposeSensitivity } from 'mastodon/actions/compose';
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
import Icon from 'mastodon/components/icon';
const messages = defineMessages({
marked: { id: 'compose_form.sensitive.marked', defaultMessage: 'Media is marked as sensitive' },
@ -38,9 +37,19 @@ class SensitiveButton extends React.PureComponent {
return (
<div className='compose-form__sensitive-button'>
<button className={classNames('icon-button', { active })} onClick={onClick} disabled={disabled} title={intl.formatMessage(active ? messages.marked : messages.unmarked)}>
<Icon id='eye-slash' /> <FormattedMessage id='compose_form.sensitive.hide' defaultMessage='Mark media as sensitive' />
</button>
<label className={classNames('icon-button', { active })} title={intl.formatMessage(active ? messages.marked : messages.unmarked)}>
<input
name='mark-sensitive'
type='checkbox'
checked={active}
onChange={onClick}
disabled={disabled}
/>
<span className={classNames('checkbox', { active })} />
<FormattedMessage id='compose_form.sensitive.hide' defaultMessage='Mark media as sensitive' />
</label>
</div>
);
}

View File

@ -3,7 +3,7 @@ import UploadButton from '../components/upload_button';
import { uploadCompose } from '../../../actions/compose';
const mapStateToProps = state => ({
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')))),
unavailable: state.getIn(['compose', 'poll']) !== null,
resetFileKey: state.getIn(['compose', 'resetFileKey']),
});

View File

@ -106,12 +106,12 @@ class Compose extends React.PureComponent {
<div className='drawer__pager'>
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
<NavigationContainer onClose={this.onBlur} />
<ComposeFormContainer />
{multiColumn && (
<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
</div>
)}
<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
</div>
</div>}
<Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>

View File

@ -56,7 +56,7 @@ class FollowRequests extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />;
return (
<Column icon='users' heading={intl.formatMessage(messages.heading)}>
<Column icon='user-plus' heading={intl.formatMessage(messages.heading)}>
<ColumnBackButtonSlim />
<ScrollableList
scrollKey='follow_requests'

View File

@ -7,12 +7,12 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me, invitesEnabled, version, profile_directory, repository, source_url } from '../../initial_state';
import { fetchFollowRequests } from '../../actions/accounts';
import { me, profile_directory } from '../../initial_state';
import { fetchFollowRequests } from 'mastodon/actions/accounts';
import { List as ImmutableList } from 'immutable';
import { Link } from 'react-router-dom';
import NavigationBar from '../compose/components/navigation_bar';
import Icon from 'mastodon/components/icon';
import LinkFooter from 'mastodon/features/ui/components/link_footer';
const messages = defineMessages({
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
@ -55,10 +55,16 @@ const badgeDisplay = (number, limit) => {
}
};
const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class GettingStarted extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object.isRequired,
};
static propTypes = {
intl: PropTypes.object.isRequired,
myAccount: ImmutablePropTypes.map.isRequired,
@ -70,7 +76,12 @@ class GettingStarted extends ImmutablePureComponent {
};
componentDidMount () {
const { myAccount, fetchFollowRequests } = this.props;
const { myAccount, fetchFollowRequests, multiColumn } = this.props;
if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) {
this.context.router.history.replace('/timelines/home');
return;
}
if (myAccount.get('locked')) {
fetchFollowRequests();
@ -123,7 +134,7 @@ class GettingStarted extends ImmutablePureComponent {
height += 48*3;
if (myAccount.get('locked')) {
navItems.push(<ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
navItems.push(<ColumnLink key={i++} icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
height += 48;
}
@ -155,27 +166,7 @@ class GettingStarted extends ImmutablePureComponent {
{!multiColumn && <div className='flex-spacer' />}
<div className='getting-started__footer'>
<ul>
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>
<li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
</ul>
<p>
<FormattedMessage
id='getting_started.open_source_notice'
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }}
/>
</p>
</div>
<LinkFooter withHotkeys={multiColumn} />
</div>
</Column>
);

View File

@ -60,6 +60,10 @@ class KeyboardShortcuts extends ImmutablePureComponent {
<td><kbd>x</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
</tr>
<tr>
<td><kbd>h</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>
</tr>
<tr>
<td><kbd>up</kbd>, <kbd>k</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>

View File

@ -75,6 +75,23 @@ class ListTimeline extends React.PureComponent {
this.disconnect = dispatch(connectListStream(id));
}
componentWillReceiveProps (nextProps) {
const { dispatch } = this.props;
const { id } = nextProps.params;
if (id !== this.props.params.id) {
if (this.disconnect) {
this.disconnect();
this.disconnect = null;
}
dispatch(fetchList(id));
dispatch(expandListTimeline(id));
this.disconnect = dispatch(connectListStream(id));
}
}
componentWillUnmount () {
if (this.disconnect) {
this.disconnect();
@ -158,8 +175,6 @@ class ListTimeline extends React.PureComponent {
<Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
</button>
</div>
<hr />
</ColumnHeader>
<StatusListContainer

View File

@ -65,11 +65,11 @@ class Lists extends ImmutablePureComponent {
<NewListForm />
<ColumnSubheading text={intl.formatMessage(messages.subheading)} />
<ScrollableList
scrollKey='lists'
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage}
prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />}
>
{lists.map(list =>
<ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} />

View File

@ -0,0 +1,17 @@
import React from 'react';
import SearchContainer from 'mastodon/features/compose/containers/search_container';
import SearchResultsContainer from 'mastodon/features/compose/containers/search_results_container';
const Search = () => (
<div className='column search-page'>
<SearchContainer />
<div className='drawer__pager'>
<div className='drawer__inner darker'>
<SearchResultsContainer />
</div>
</div>
</div>
);
export default Search;

View File

@ -13,7 +13,6 @@ import Video from '../../video';
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import PollContainer from 'mastodon/containers/poll_container';
export default class DetailedStatus extends ImmutablePureComponent {
@ -30,6 +29,8 @@ export default class DetailedStatus extends ImmutablePureComponent {
onHeightChange: PropTypes.func,
domain: PropTypes.string.isRequired,
compact: PropTypes.bool,
showMedia: PropTypes.bool,
onToggleMediaVisibility: PropTypes.func,
};
state = {
@ -105,23 +106,23 @@ export default class DetailedStatus extends ImmutablePureComponent {
outerStyle.height = `${this.state.height}px`;
}
if (status.get('poll')) {
media = <PollContainer pollId={status.get('poll')} />;
} else if (status.get('media_attachments').size > 0) {
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
const video = status.getIn(['media_attachments', 0]);
if (status.get('media_attachments').size > 0) {
if (['video', 'audio'].includes(status.getIn(['media_attachments', 0, 'type']))) {
const attachment = status.getIn(['media_attachments', 0]);
media = (
<Video
preview={video.get('preview_url')}
blurhash={video.get('blurhash')}
src={video.get('url')}
alt={video.get('description')}
preview={attachment.get('preview_url')}
blurhash={attachment.get('blurhash')}
src={attachment.get('url')}
alt={attachment.get('description')}
width={300}
height={150}
inline
onOpenVideo={this.handleOpenVideo}
sensitive={status.get('sensitive')}
visible={this.props.showMedia}
onToggleVisibility={this.props.onToggleMediaVisibility}
/>
);
} else {
@ -132,6 +133,8 @@ export default class DetailedStatus extends ImmutablePureComponent {
media={status.get('media_attachments')}
height={300}
onOpenMedia={this.props.onOpenMedia}
visible={this.props.showMedia}
onToggleVisibility={this.props.onToggleMediaVisibility}
/>
);
}

View File

@ -43,7 +43,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys';
import { boostModal, deleteModal } from '../../initial_state';
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
import { textForScreenReader } from '../../components/status';
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import Icon from 'mastodon/components/icon';
const messages = defineMessages({
@ -131,6 +131,8 @@ class Status extends ImmutablePureComponent {
state = {
fullscreen: false,
showMedia: defaultMediaVisibility(this.props.status),
loadedStatusId: undefined,
};
componentWillMount () {
@ -146,6 +148,14 @@ class Status extends ImmutablePureComponent {
this._scrolledIntoView = false;
this.props.dispatch(fetchStatus(nextProps.params.statusId));
}
if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) {
this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get('id') });
}
}
handleToggleMediaVisibility = () => {
this.setState({ showMedia: !this.state.showMedia });
}
handleFavouriteClick = (status) => {
@ -312,6 +322,10 @@ class Status extends ImmutablePureComponent {
this.handleToggleHidden(this.props.status);
}
handleHotkeyToggleSensitive = () => {
this.handleToggleMediaVisibility();
}
handleMoveUp = id => {
const { status, ancestorsIds, descendantsIds } = this.props;
@ -432,6 +446,7 @@ class Status extends ImmutablePureComponent {
mention: this.handleHotkeyMention,
openProfile: this.handleHotkeyOpenProfile,
toggleHidden: this.handleHotkeyToggleHidden,
toggleSensitive: this.handleHotkeyToggleSensitive,
};
return (
@ -455,6 +470,8 @@ class Status extends ImmutablePureComponent {
onOpenMedia={this.handleOpenMedia}
onToggleHidden={this.handleToggleHidden}
domain={domain}
showMedia={this.state.showMedia}
onToggleMediaVisibility={this.handleToggleMediaVisibility}
/>
<ActionBar

View File

@ -9,8 +9,10 @@ import RelativeTimestamp from '../../../components/relative_timestamp';
import DisplayName from '../../../components/display_name';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Icon from 'mastodon/components/icon';
import AttachmentList from 'mastodon/components/attachment_list';
const messages = defineMessages({
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
});
@ -51,6 +53,7 @@ class BoostModal extends ImmutablePureComponent {
render () {
const { status, intl } = this.props;
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
return (
<div className='modal-root__modal boost-modal'>
@ -71,12 +74,19 @@ class BoostModal extends ImmutablePureComponent {
</div>
<StatusContent status={status} />
{status.get('media_attachments').size > 0 && (
<AttachmentList
compact
media={status.get('media_attachments')}
/>
)}
</div>
</div>
<div className='boost-modal__action-bar'>
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
<Button text={intl.formatMessage(messages.reblog)} onClick={this.handleReblog} ref={this.setRef} />
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
</div>
</div>
);

View File

@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ReactSwipeableViews from 'react-swipeable-views';
import { links, getIndex, getLink } from './tabs_bar';
import TabsBar, { links, getIndex, getLink } from './tabs_bar';
import { Link } from 'react-router-dom';
import BundleContainer from '../containers/bundle_container';
@ -14,6 +14,8 @@ import DrawerLoading from './drawer_loading';
import BundleColumnError from './bundle_column_error';
import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses, ListTimeline } from '../../ui/util/async-components';
import Icon from 'mastodon/components/icon';
import ComposePanel from './compose_panel';
import NavigationPanel from './navigation_panel';
import detectPassiveEvents from 'detect-passive-events';
import { scrollRight } from '../../../scroll';
@ -139,7 +141,7 @@ class ColumnsArea extends ImmutablePureComponent {
<ColumnLoading title={title} icon={icon} />;
return (
<div className='columns-area' key={index}>
<div className='columns-area columns-area--mobile' key={index}>
{view}
</div>
);
@ -163,17 +165,36 @@ class ColumnsArea extends ImmutablePureComponent {
if (singleColumn) {
const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>;
return columnIndex !== -1 ? [
const content = columnIndex !== -1 ? (
<ReactSwipeableViews key='content' index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }}>
{links.map(this.renderView)}
</ReactSwipeableViews>,
</ReactSwipeableViews>
) : (
<div key='content' className='columns-area columns-area--mobile'>{children}</div>
);
floatingActionButton,
] : [
<div className='columns-area'>{children}</div>,
return (
<div className='columns-area__panels'>
<div className='columns-area__panels__pane columns-area__panels__pane--compositional'>
<div className='columns-area__panels__pane__inner'>
<ComposePanel />
</div>
</div>
floatingActionButton,
];
<div className='columns-area__panels__main'>
<TabsBar key='tabs' />
{content}
</div>
<div className='columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational'>
<div className='columns-area__panels__pane__inner'>
<NavigationPanel />
</div>
</div>
{floatingActionButton}
</div>
);
}
return (

View File

@ -0,0 +1,16 @@
import React from 'react';
import SearchContainer from 'mastodon/features/compose/containers/search_container';
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
import NavigationContainer from 'mastodon/features/compose/containers/navigation_container';
import LinkFooter from './link_footer';
const ComposePanel = () => (
<div className='compose-panel'>
<SearchContainer openInRoute />
<NavigationContainer />
<ComposeFormContainer singleColumn />
<LinkFooter withHotkeys />
</div>
);
export default ComposePanel;

View File

@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import { fetchFollowRequests } from 'mastodon/actions/accounts';
import { connect } from 'react-redux';
import { NavLink, withRouter } from 'react-router-dom';
import IconWithBadge from 'mastodon/components/icon_with_badge';
import { me } from 'mastodon/initial_state';
import { List as ImmutableList } from 'immutable';
import { FormattedMessage } from 'react-intl';
const mapStateToProps = state => ({
locked: state.getIn(['accounts', me, 'locked']),
count: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
});
export default @withRouter
@connect(mapStateToProps)
class FollowRequestsNavLink extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
locked: PropTypes.bool,
count: PropTypes.number.isRequired,
};
componentDidMount () {
const { dispatch, locked } = this.props;
if (locked) {
dispatch(fetchFollowRequests());
}
}
render () {
const { locked, count } = this.props;
if (!locked || count === 0) {
return null;
}
return <NavLink className='column-link column-link--transparent' to='/follow_requests'><IconWithBadge className='column-link__icon' id='user-plus' count={count} /><FormattedMessage id='navigation_bar.follow_requests' defaultMessage='Follow requests' /></NavLink>;
}
}

View File

@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import { invitesEnabled, version, repository, source_url } from 'mastodon/initial_state';
const LinkFooter = ({ withHotkeys }) => (
<div className='getting-started__footer'>
<ul>
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
{withHotkeys && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>
<li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
</ul>
<p>
<FormattedMessage
id='getting_started.open_source_notice'
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }}
/>
</p>
</div>
);
LinkFooter.propTypes = {
withHotkeys: PropTypes.bool,
};
export default LinkFooter;

View File

@ -0,0 +1,55 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { fetchLists } from 'mastodon/actions/lists';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { NavLink, withRouter } from 'react-router-dom';
import Icon from 'mastodon/components/icon';
const getOrderedLists = createSelector([state => state.get('lists')], lists => {
if (!lists) {
return lists;
}
return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title'))).take(4);
});
const mapStateToProps = state => ({
lists: getOrderedLists(state),
});
export default @withRouter
@connect(mapStateToProps)
class ListPanel extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
lists: ImmutablePropTypes.list,
};
componentDidMount () {
const { dispatch } = this.props;
dispatch(fetchLists());
}
render () {
const { lists } = this.props;
if (!lists || lists.isEmpty()) {
return null;
}
return (
<div>
<hr />
{lists.map(list => (
<NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/timelines/list/${list.get('id')}`}><Icon className='column-link__icon' id='list-ul' fixedWidth />{list.get('title')}</NavLink>
))}
</div>
);
}
}

View File

@ -0,0 +1,31 @@
import React from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { profile_directory } from 'mastodon/initial_state';
import NotificationsCounterIcon from './notifications_counter_icon';
import FollowRequestsNavLink from './follow_requests_nav_link';
import ListPanel from './list_panel';
const NavigationPanel = () => (
<div className='navigation-panel'>
<NavLink className='column-link column-link--transparent' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>
<FollowRequestsNavLink />
<NavLink className='column-link column-link--transparent' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>
<NavLink className='column-link column-link--transparent' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/timelines/direct'><Icon className='column-link__icon' id='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' id='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink>
<ListPanel />
<hr />
<a className='column-link column-link--transparent' href='/settings/preferences'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>
<a className='column-link column-link--transparent' href='/relationships'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>
{!!profile_directory && <a className='column-link column-link--transparent' href='/explore'><Icon className='column-link__icon' id='address-book-o' fixedWidth /><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></a>}
</div>
);
export default withRouter(NavigationPanel);

View File

@ -0,0 +1,9 @@
import { connect } from 'react-redux';
import IconWithBadge from 'mastodon/components/icon_with_badge';
const mapStateToProps = state => ({
count: state.getIn(['notifications', 'unread']),
id: 'bell',
});
export default connect(mapStateToProps)(IconWithBadge);

View File

@ -5,16 +5,15 @@ import { FormattedMessage, injectIntl } from 'react-intl';
import { debounce } from 'lodash';
import { isUserTouching } from '../../../is_mobile';
import Icon from 'mastodon/components/icon';
import NotificationsCounterIcon from './notifications_counter_icon';
export const links = [
<NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
<NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><Icon id='bell' fixedWidth /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
<NavLink className='tabs-bar__link secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
<NavLink className='tabs-bar__link secondary' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
<NavLink className='tabs-bar__link primary' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
<NavLink className='tabs-bar__link primary' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>,
<NavLink className='tabs-bar__link' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
<NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
<NavLink className='tabs-bar__link' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
<NavLink className='tabs-bar__link' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
<NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
<NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>,
];
export function getIndex (path) {

View File

@ -7,7 +7,6 @@ import { Redirect, withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import NotificationsContainer from './containers/notifications_container';
import LoadingBarContainer from './containers/loading_bar_container';
import TabsBar from './components/tabs_bar';
import ModalContainer from './containers/modal_container';
import { isMobile } from '../../is_mobile';
import { debounce } from 'lodash';
@ -45,8 +44,9 @@ import {
Mutes,
PinnedStatuses,
Lists,
Search,
} from './util/async-components';
import { me } from '../../initial_state';
import { me, forceSingleColumn } from '../../initial_state';
import { previewState as previewMediaState } from './components/media_modal';
import { previewState as previewVideoState } from './components/video_modal';
@ -93,6 +93,7 @@ const keyMap = {
goToMuted: 'g m',
goToRequests: 'g r',
toggleHidden: 'x',
toggleSensitive: 'h',
};
class SwitchingColumnsArea extends React.PureComponent {
@ -141,10 +142,11 @@ class SwitchingColumnsArea extends React.PureComponent {
render () {
const { children } = this.props;
const { mobile } = this.state;
const redirect = mobile ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
const singleColumn = forceSingleColumn || mobile;
const redirect = singleColumn ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
return (
<ColumnsAreaContainer ref={this.setRef} singleColumn={mobile}>
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
<WrappedSwitch>
{redirect}
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
@ -160,7 +162,7 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/search' component={Compose} content={children} componentParams={{ isSearchPage: true }} />
<WrappedRoute path='/search' component={Search} content={children} />
<WrappedRoute path='/statuses/new' component={Compose} content={children} />
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
@ -479,8 +481,6 @@ class UI extends React.PureComponent {
return (
<HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
<TabsBar />
<SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange}>
{children}
</SwitchingColumnsArea>

View File

@ -129,3 +129,7 @@ export function ListEditor () {
export function ListAdder () {
return import(/*webpackChunkName: "features/list_adder" */'../../list_adder');
}
export function Search () {
return import(/*webpackChunkName: "features/search" */'../../search');
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { fromJS } from 'immutable';
import { fromJS, is } from 'immutable';
import { throttle } from 'lodash';
import classNames from 'classnames';
import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
@ -102,6 +102,8 @@ class Video extends React.PureComponent {
detailed: PropTypes.bool,
inline: PropTypes.bool,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
intl: PropTypes.object.isRequired,
blurhash: PropTypes.string,
link: PropTypes.node,
@ -117,7 +119,7 @@ class Video extends React.PureComponent {
fullscreen: false,
hovered: false,
muted: false,
revealed: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
};
// hard coded in components.scss
@ -280,7 +282,16 @@ class Video extends React.PureComponent {
document.removeEventListener('MSFullscreenChange', this.handleFullscreenChange, true);
}
componentDidUpdate (prevProps) {
componentWillReceiveProps (nextProps) {
if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
this.setState({ revealed: nextProps.visible });
}
}
componentDidUpdate (prevProps, prevState) {
if (prevState.revealed && !this.state.revealed && this.video) {
this.video.pause();
}
if (prevProps.blurhash !== this.props.blurhash && this.props.blurhash) {
this._decode();
}
@ -316,11 +327,11 @@ class Video extends React.PureComponent {
}
toggleReveal = () => {
if (this.state.revealed) {
this.video.pause();
if (this.props.onToggleVisibility) {
this.props.onToggleVisibility();
} else {
this.setState({ revealed: !this.state.revealed });
}
this.setState({ revealed: !this.state.revealed });
}
handleLoadedData = () => {

View File

@ -19,5 +19,6 @@ export const version = getMeta('version');
export const mascot = getMeta('mascot');
export const profile_directory = getMeta('profile_directory');
export const isStaff = getMeta('is_staff');
export const forceSingleColumn = !getMeta('advanced_layout');
export default initialState;

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