Compare commits

...

114 Commits

Author SHA1 Message Date
Thor 6b224840bc Merge remote-tracking branch 'upstream/main' into main 1 year ago
Thor abfbb2d3f2 Make 'tootctl media remove-orphans' retry file listings 1 year ago
Claire dc02a93d04
Merge pull request #2105 from ClearlyClaire/glitch-soc/merge-upstream 1 year ago
Claire 87419f9307 Merge branch 'main' into glitch-soc/merge-upstream 1 year ago
Claire 61c5dfb929
Update changelog (#23515) 1 year ago
Claire 70c0d754a6
Bump version to 4.1.0 (#23471) 1 year ago
Claire 0c9eac80d8
Fix unbounded recursion in post discovery (#23506) 1 year ago
Nick Schonning 719bb799be
Remove DesspSouce config (#23513) 1 year ago
Claire bae17ebe5e
Fix attached media uploads not being cleared when replying to a post (#23504) 1 year ago
Eugen Rochko 71ae17e8f5
New Crowdin updates (#23413) 1 year ago
Claire 4ceadc65b0 Merge branch 'main' into glitch-soc/merge-upstream 1 year ago
Claire a9c220242b
Fix admin-set follow recommandations being case-sensitive (#23500) 1 year ago
Claire 67de888bad
Fix server status URL being a required server setting (#23499) 1 year ago
Nick Schonning f23d30100a
Cleanup unused i18n strings (#23426) 1 year ago
cadars 5e37906083 [Glitch] Add scrolling to Compare history modal 1 year ago
Christian Schmidt 2dfbdc3f9d [Glitch] Show spinner while loading follow requests 1 year ago
Christian Schmidt 8fd6c36243 [Glitch] Spell check input fields 1 year ago
Eugen Rochko 95e2cab22e [Glitch] Add setting for status page URL 1 year ago
Claire 85558a5e18 Merge branch 'main' into glitch-soc/merge-upstream 1 year ago
Eugen Rochko c5a4d8c82d
Add information about database pool to metrics endpoint in streaming API (#23469) 1 year ago
Eugen Rochko 4cb7647516
Add database pool configuration over `DB_POOL` to streaming API (#23470) 1 year ago
Claire 832595d1e7
Remove posts count and last posts from ActivityPub representation of hashtag collections (#23460) 1 year ago
dependabot[bot] 08001e387b
Bump axios from 1.2.6 to 1.3.2 (#23420) 1 year ago
Nick Schonning 0592937264
Apply Rubocop Rails/WhereNot (#23448) 1 year ago
Nick Schonning 11557d1c5a
Apply Rubocop Rails/RootPublicPath (#23447) 1 year ago
Nick Schonning 0d1f192c54
Apply Rubocop Performance/BlockGivenWithExplicitBlock (#23441) 1 year ago
Nick Schonning 26ac2447b4
Apply Rubocop Style/EmptyElse (#23449) 1 year ago
Nick Schonning f68bb52556
Apply Rubocop Style/NegatedIfElseCondition (#23451) 1 year ago
Nick Schonning 8c1b65c7dd
Apply Rubocop Style/RedundantAssignment (#23452) 1 year ago
Nick Schonning 1487fcde93
Apply Rubocop Style/ExpandPathArguments (#23450) 1 year ago
Nick Schonning d3f59f52c3
Apply Rubocop Performance/StringReplacement (#23445) 1 year ago
Nick Schonning 203739dd3a
Apply Rubocop Performance/StringIdentifierArgument (#23444) 1 year ago
Nick Schonning 2e652aa81c
Apply Rubocop Performance/RedundantSplitRegexpArgument (#23443) 1 year ago
Nick Schonning ef8988aef2
Apply Rubocop Performance/DoubleStartEndWith (#23442) 1 year ago
Nick Schonning c92e033cdd
Apply Rubocop Performance/BindCall (#23437) 1 year ago
Nick Schonning cec005068f
Apply Rubocop Performance/RedundantBlockCall (#23440) 1 year ago
dependabot[bot] f31d9a590d
Bump sass from 1.57.1 to 1.58.0 (#23421) 1 year ago
dependabot[bot] e559d1e672
Bump rubocop-performance from 1.15.2 to 1.16.0 (#23418) 1 year ago
dependabot[bot] 1e2f839543
Bump immutable from 4.2.2 to 4.2.4 (#23419) 1 year ago
dependabot[bot] ea4ff7e786
Bump doorkeeper from 5.6.3 to 5.6.4 (#23422) 1 year ago
dependabot[bot] fb7919e4ec
Bump webpacker from 5.4.3 to 5.4.4 (#23424) 1 year ago
dependabot[bot] 4f14957723
Bump faker from 3.1.0 to 3.1.1 (#23425) 1 year ago
Nick Schonning ed570050c6
Autofix Rails/EagerEvaluationLogMessage (#23429) 1 year ago
mon1kasenpai 6a71bb23c2
Update README.md (#23409) 1 year ago
Claire 9edefc779f
Fix `UserCleanupScheduler` crash when an unconfirmed account has a moderation note (#23318) 1 year ago
Jeong Arm 523a86618f
Fix account serializer crash if account doesn't have a user (#23428) 1 year ago
Claire bb89f0af8a
Fix ActivityPub::ProcessingWorker error on incoming malformed JSON-LD (#23416) 1 year ago
Eugen Rochko e2207af3d7
New Crowdin updates (#23393) 1 year ago
cadars e8cb3ee827
Add scrolling to Compare history modal (#23396) 1 year ago
Christian Schmidt c1f32c9c14
Show spinner while loading follow requests (#23386) 1 year ago
Claire 76b4e7727b
Merge pull request #2101 from ClearlyClaire/glitch-soc/merge-upstream 1 year ago
Claire fa433ac5a6 Further JS code style changes 1 year ago
Christian Schmidt 67744ee779
Spell check input fields (#23395) 1 year ago
dependabot[bot] 1f9f8035e4
Bump bootsnap from 1.15.0 to 1.16.0 (#23340) 1 year ago
Eugen Rochko 8651ef751e
New Crowdin updates (#23356) 1 year ago
Eugen Rochko 8f590b0a21
Add setting for status page URL (#23390) 1 year ago
Eugen Rochko 01584f03e8
Add metrics endpoint to streaming API (#23388) 1 year ago
Claire 3c451cf88f [Glitch] Fix useless regular-expression character escape detected by CodeQL 1 year ago
Akira Ouchi 8ce02aa6e8 [Glitch] autofocus the compose form again on /share 1 year ago
Nick Schonning 372fa3fe36 [Glitch] Update hasOwnProperty calls for ESLint 1 year ago
Claire 155424e52f [Glitch] Run eslint --fix 1 year ago
Nick Schonning ed7cb79723 [Glitch] Remove extra semicolons with ESLint autofix 1 year ago
TAKAHASHI Shuuji 1d5395498d [Glitch] chore: remove intersection-observer for old Safari support 1 year ago
Christian Schmidt fb9c786baf [Glitch] Add lang attribute to image description textarea and poll option field 1 year ago
Claire aeacebb3d7 Merge branch 'main' into glitch-soc/merge-upstream 1 year ago
Claire 79ca19e9b2
Bump version to 4.1.0rc3 (#23384) 1 year ago
Eugen Rochko f98e4c662e
Change link previews for statuses to never use avatar as fallback (#23376) 1 year ago
Elizabeth Martín Campos 7e04b15ad8
fix(web-push-notifications): fix favourite push notifications (#23286) 1 year ago
Claire 20a479ff7c
Change `POST /settings/applications/:id` to regenerate token on scopes change (#23359) 1 year ago
Nick Schonning 6a5e447753
Address check-i18n warnings (#23313) 1 year ago
Eugen Rochko c6ef56fd5e
Change rate limits to 1,500/5m per user, 300/5m per app (#23347) 1 year ago
Yamagishi Kazutoshi 420f33ccb9
Skip locales linting (#23352) 1 year ago
Claire 1c335ac53a
Fix official docker images nto being compatible with some cloud providers (#23354) 1 year ago
dependabot[bot] 9400bdbce5
Bump docker/build-push-action from 3 to 4 (#23333) 1 year ago
Eugen Rochko b8c31f8110
New Crowdin updates (#23221) 1 year ago
dependabot[bot] e79babe6a3
Bump jest-environment-jsdom from 29.3.1 to 29.4.1 (#23329) 1 year ago
dependabot[bot] fe4e2e0bd1
Bump babel-jest from 29.3.1 to 29.4.1 (#23331) 1 year ago
dependabot[bot] 842d89fda8
Bump jest from 29.3.1 to 29.4.1 (#23335) 1 year ago
dependabot[bot] 05f5e5ae6f
Bump nokogiri from 1.14.0 to 1.14.1 (#23330) 1 year ago
dependabot[bot] 91ceb8af11
Bump ox from 2.14.13 to 2.14.14 (#23338) 1 year ago
Eugen Rochko 4c919812b9
Change number of stored items in home feed from 400 to 800 (#23349) 1 year ago
Eugen Rochko 21780c0204
Change notifications per page from 15 to 40 in REST API (#23348) 1 year ago
dependabot[bot] 41baf4b217
Bump redcarpet from 3.5.1 to 3.6.0 (#23339) 1 year ago
dependabot[bot] 784961059c
Bump eslint-plugin-react from 7.32.1 to 7.32.2 (#23336) 1 year ago
dependabot[bot] c38d685c41
Bump axios from 1.2.3 to 1.2.6 (#23334) 1 year ago
dependabot[bot] fa379a993d
Bump aws-sdk-s3 from 1.118.0 to 1.119.0 (#23341) 1 year ago
dependabot[bot] 723412ac5e
Bump rubocop from 1.44.0 to 1.44.1 (#23337) 1 year ago
dependabot[bot] 597daed17a
Bump rimraf from 4.1.1 to 4.1.2 (#23332) 1 year ago
dependabot[bot] f684ff72f2
Bump utf-8-validate from 6.0.1 to 6.0.2 (#23327) 1 year ago
dependabot[bot] 801a209e06
Bump simple_form from 5.1.0 to 5.2.0 (#23328) 1 year ago
dependabot[bot] d49879cc7b
Bump rails from 6.1.7.1 to 6.1.7.2 (#23326) 1 year ago
dependabot[bot] 4b6bd4bc0d
Bump redux from 4.2.0 to 4.2.1 (#23325) 1 year ago
dependabot[bot] 409fcd1985
Bump doorkeeper from 5.6.2 to 5.6.3 (#23324) 1 year ago
dependabot[bot] 081f14b361
Bump mkdirp from 1.0.4 to 2.1.3 (#23228) 1 year ago
dependabot[bot] 1ca3127a1d
Bump gitlab-omniauth-openid-connect from 0.10.0 to 0.10.1 (#23241) 1 year ago
Akira Ouchi e73b55184b
autofocus the compose form again on /share (#23094) 1 year ago
Nick Schonning 96d26a9417
Enable ESLint jsx-a11y/recommended ruleset (#23309) 1 year ago
Nick Schonning 1032d45644
Ignore ESLint nested ternary (#23310) 1 year ago
dependabot[bot] f8bdfa2f19
Bump punycode from 2.2.0 to 2.3.0 (#23230) 1 year ago
dependabot[bot] 84c72cb21f
Bump eslint-plugin-jsx-a11y from 6.6.1 to 6.7.1 (#23121) 1 year ago
Nick Schonning cbf5ea39d0
Enable ESLint react/recommended ruleset (#22460) 1 year ago
Nick Schonning 131e6403cc
Update hasOwnProperty calls for ESLint (#23307) 1 year ago
Nick Schonning 56d1af753d
Only build latest commit on branch for image (#23306) 1 year ago
dependabot[bot] ea1507ee85
Bump aws-sdk-s3 from 1.117.2 to 1.118.0 (#23202) 1 year ago
dependabot[bot] 8ce2a4220c
Bump eslint-plugin-import from 2.26.0 to 2.27.5 (#23120) 1 year ago
Nick Schonning e6192eab9b
Remove unused ESLint disable directives (#22427) 1 year ago
Nick Schonning c49213f0ea
Upgrade ESlint to v8 (#23305) 1 year ago
Nick Schonning b58bf74e35
Filter Superlinter to Ruby files only (#21976) 1 year ago
Nick Schonning 4917e38d94
Separate Stylelint from Superlinter (#23303) 1 year ago
Nick Schonning d9088ef327
Separate ESLint CI from Superlinter (#23029) 1 year ago
TAKAHASHI Shuuji 9cdd643564
chore: remove intersection-observer for old Safari support (#23284) 1 year ago
Christian Schmidt 2a4f2216d6
Add lang attribute to image description textarea and poll option field (#23293) 1 year ago
Eugen Rochko d3f3810fe1
Fix unserialized `role` on account entities in admin API (#23290) 1 year ago
dependabot[bot] 1708167dd3
Bump sanitize from 6.0.0 to 6.0.1 (#23281) 1 year ago
  1. 23
      .deepsource.toml
  2. 87
      .eslintrc.js
  3. 8
      .github/workflows/build-image.yml
  4. 2
      .github/workflows/check-i18n.yml
  5. 48
      .github/workflows/lint-css.yml
  6. 40
      .github/workflows/lint-js.yml
  7. 2
      .github/workflows/lint-json.yml
  8. 41
      .github/workflows/lint-ruby.yml
  9. 2
      .github/workflows/lint-yml.yml
  10. 83
      .github/workflows/linter.yml
  11. 56
      CHANGELOG.md
  12. 10
      Gemfile
  13. 178
      Gemfile.lock
  14. 2
      app/controllers/api/v1/notifications_controller.rb
  15. 6
      app/controllers/api/v1/streaming_controller.rb
  16. 2
      app/controllers/concerns/signature_verification.rb
  17. 8
      app/controllers/settings/applications_controller.rb
  18. 11
      app/controllers/tags_controller.rb
  19. 4
      app/helpers/application_helper.rb
  20. 2
      app/helpers/email_helper.rb
  21. 4
      app/helpers/jsonld_helper.rb
  22. 4
      app/helpers/languages_helper.rb
  23. 2
      app/javascript/core/embed.js
  24. 4
      app/javascript/core/settings.js
  25. 14
      app/javascript/flavours/glitch/actions/account_notes.js
  26. 166
      app/javascript/flavours/glitch/actions/accounts.js
  27. 6
      app/javascript/flavours/glitch/actions/alerts.js
  28. 16
      app/javascript/flavours/glitch/actions/blocks.js
  29. 16
      app/javascript/flavours/glitch/actions/bookmarks.js
  30. 2
      app/javascript/flavours/glitch/actions/boosts.js
  31. 6
      app/javascript/flavours/glitch/actions/columns.js
  32. 92
      app/javascript/flavours/glitch/actions/compose.js
  33. 8
      app/javascript/flavours/glitch/actions/custom_emojis.js
  34. 32
      app/javascript/flavours/glitch/actions/domain_blocks.js
  35. 2
      app/javascript/flavours/glitch/actions/emojis.js
  36. 16
      app/javascript/flavours/glitch/actions/favourites.js
  37. 4
      app/javascript/flavours/glitch/actions/height_cache.js
  38. 80
      app/javascript/flavours/glitch/actions/interactions.js
  39. 10
      app/javascript/flavours/glitch/actions/local_settings.js
  40. 10
      app/javascript/flavours/glitch/actions/markers.js
  41. 4
      app/javascript/flavours/glitch/actions/modal.js
  42. 16
      app/javascript/flavours/glitch/actions/mutes.js
  43. 40
      app/javascript/flavours/glitch/actions/notifications.js
  44. 2
      app/javascript/flavours/glitch/actions/onboarding.js
  45. 8
      app/javascript/flavours/glitch/actions/pin_statuses.js
  46. 12
      app/javascript/flavours/glitch/actions/search.js
  47. 4
      app/javascript/flavours/glitch/actions/settings.js
  48. 48
      app/javascript/flavours/glitch/actions/statuses.js
  49. 4
      app/javascript/flavours/glitch/actions/store.js
  50. 8
      app/javascript/flavours/glitch/actions/suggestions.js
  51. 14
      app/javascript/flavours/glitch/actions/tags.js
  52. 20
      app/javascript/flavours/glitch/actions/timelines.js
  53. 2
      app/javascript/flavours/glitch/compare_id.js
  54. 12
      app/javascript/flavours/glitch/components/account.js
  55. 2
      app/javascript/flavours/glitch/components/admin/Retention.js
  56. 4
      app/javascript/flavours/glitch/components/animated_number.js
  57. 18
      app/javascript/flavours/glitch/components/autosuggest_input.js
  58. 16
      app/javascript/flavours/glitch/components/autosuggest_textarea.js
  59. 4
      app/javascript/flavours/glitch/components/avatar.js
  60. 4
      app/javascript/flavours/glitch/components/button.js
  61. 4
      app/javascript/flavours/glitch/components/column.js
  62. 2
      app/javascript/flavours/glitch/components/column_back_button.js
  63. 2
      app/javascript/flavours/glitch/components/column_back_button_slim.js
  64. 16
      app/javascript/flavours/glitch/components/column_header.js
  65. 2
      app/javascript/flavours/glitch/components/dismissable_banner.js
  66. 6
      app/javascript/flavours/glitch/components/display_name.js
  67. 2
      app/javascript/flavours/glitch/components/domain.js
  68. 34
      app/javascript/flavours/glitch/components/dropdown_menu.js
  69. 4
      app/javascript/flavours/glitch/components/edited_timestamp/index.js
  70. 2
      app/javascript/flavours/glitch/components/error_boundary.js
  71. 4
      app/javascript/flavours/glitch/components/gifv.js
  72. 10
      app/javascript/flavours/glitch/components/icon_button.js
  73. 17
      app/javascript/flavours/glitch/components/intersection_observer_article.js
  74. 2
      app/javascript/flavours/glitch/components/load_gap.js
  75. 4
      app/javascript/flavours/glitch/components/load_more.js
  76. 2
      app/javascript/flavours/glitch/components/load_pending.js
  77. 6
      app/javascript/flavours/glitch/components/media_attachments.js
  78. 18
      app/javascript/flavours/glitch/components/media_gallery.js
  79. 9
      app/javascript/flavours/glitch/components/modal_root.js
  80. 4
      app/javascript/flavours/glitch/components/permalink.js
  81. 4
      app/javascript/flavours/glitch/components/picture_in_picture_placeholder.js
  82. 4
      app/javascript/flavours/glitch/components/poll.js
  83. 22
      app/javascript/flavours/glitch/components/scrollable_list.js
  84. 2
      app/javascript/flavours/glitch/components/setting_text.js
  85. 30
      app/javascript/flavours/glitch/components/spoilers.js
  86. 64
      app/javascript/flavours/glitch/components/status.js
  87. 44
      app/javascript/flavours/glitch/components/status_action_bar.js
  88. 26
      app/javascript/flavours/glitch/components/status_content.js
  89. 4
      app/javascript/flavours/glitch/components/status_header.js
  90. 22
      app/javascript/flavours/glitch/components/status_icons.js
  91. 12
      app/javascript/flavours/glitch/components/status_list.js
  92. 6
      app/javascript/flavours/glitch/components/status_prepend.js
  93. 8
      app/javascript/flavours/glitch/containers/media_container.js
  94. 1
      app/javascript/flavours/glitch/extra_polyfills.js
  95. 4
      app/javascript/flavours/glitch/features/about/index.js
  96. 2
      app/javascript/flavours/glitch/features/account/components/account_note.js
  97. 4
      app/javascript/flavours/glitch/features/account/components/action_bar.js
  98. 15
      app/javascript/flavours/glitch/features/account/components/header.js
  99. 8
      app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
  100. 16
      app/javascript/flavours/glitch/features/account_gallery/index.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,23 +0,0 @@
version = 1
test_patterns = ["app/javascript/mastodon/**/__tests__/**"]
exclude_patterns = [
"db/migrate/**",
"db/post_migrate/**"
]
[[analyzers]]
name = "ruby"
enabled = true
[[analyzers]]
name = "javascript"
enabled = true
[analyzers.meta]
environment = [
"browser",
"jest",
"nodejs"
]

@ -3,6 +3,8 @@ module.exports = {
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:jsx-a11y/recommended',
],
env: {
@ -80,8 +82,6 @@ module.exports = {
},
],
'no-empty': 'off',
'no-nested-ternary': 'warn',
'no-prototype-builtins': 'off',
'no-restricted-properties': [
'error',
{ property: 'substring', message: 'Use .slice instead of .substring.' },
@ -113,55 +113,42 @@ module.exports = {
'react/jsx-boolean-value': 'error',
'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
'react/jsx-curly-spacing': 'error',
'react/display-name': 'off',
'react/jsx-equals-spacing': 'error',
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
'react/jsx-indent': ['error', 2],
'react/jsx-no-bind': 'error',
'react/jsx-no-duplicate-props': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-no-target-blank': 'off',
'react/jsx-tag-spacing': 'error',
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'react/jsx-wrap-multilines': 'error',
'react/no-multi-comp': 'off',
'react/no-string-refs': 'error',
'react/prop-types': 'error',
'react/no-deprecated': 'off',
'react/no-unknown-property': 'off',
'react/self-closing-comp': 'error',
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js
'jsx-a11y/accessible-emoji': 'warn',
'jsx-a11y/alt-text': 'warn',
'jsx-a11y/anchor-has-content': 'warn',
'jsx-a11y/anchor-is-valid': [
'warn',
{
components: [
'Link',
'NavLink',
],
specialLink: [
'to',
],
aspect: [
'noHref',
'invalidHref',
'preferButton',
],
},
],
'jsx-a11y/aria-activedescendant-has-tabindex': 'warn',
'jsx-a11y/aria-props': 'warn',
'jsx-a11y/aria-proptypes': 'warn',
'jsx-a11y/aria-role': 'warn',
'jsx-a11y/aria-unsupported-elements': 'warn',
'jsx-a11y/heading-has-content': 'warn',
'jsx-a11y/html-has-lang': 'warn',
'jsx-a11y/iframe-has-title': 'warn',
'jsx-a11y/img-redundant-alt': 'warn',
'jsx-a11y/interactive-supports-focus': 'warn',
'jsx-a11y/label-has-for': 'off',
'jsx-a11y/mouse-events-have-key-events': 'warn',
'jsx-a11y/no-access-key': 'warn',
'jsx-a11y/no-distracting-elements': 'warn',
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/label-has-associated-control': 'off',
'jsx-a11y/media-has-caption': 'off',
'jsx-a11y/no-autofocus': 'off',
// recommended rule is:
// 'jsx-a11y/no-interactive-element-to-noninteractive-role': [
// 'error',
// {
// tr: ['none', 'presentation'],
// canvas: ['img'],
// },
// ],
'jsx-a11y/no-interactive-element-to-noninteractive-role': 'off',
// recommended rule is:
// 'jsx-a11y/no-noninteractive-element-interactions': [
// 'error',
// {
// body: ['onError', 'onLoad'],
// iframe: ['onError', 'onLoad'],
// img: ['onError', 'onLoad'],
// },
// ],
'jsx-a11y/no-noninteractive-element-interactions': [
'warn',
{
@ -170,8 +157,18 @@ module.exports = {
],
},
],
// recommended rule is:
// 'jsx-a11y/no-noninteractive-tabindex': [
// 'error',
// {
// tags: [],
// roles: ['tabpanel'],
// allowExpressionValues: true,
// },
// ],
'jsx-a11y/no-noninteractive-tabindex': 'off',
'jsx-a11y/no-onchange': 'warn',
'jsx-a11y/no-redundant-roles': 'warn',
// recommended is full 'error'
'jsx-a11y/no-static-element-interactions': [
'warn',
{
@ -180,10 +177,6 @@ module.exports = {
],
},
],
'jsx-a11y/role-has-required-aria-props': 'warn',
'jsx-a11y/role-supports-aria-props': 'off',
'jsx-a11y/scope': 'warn',
'jsx-a11y/tabindex-no-positive': 'warn',
'import/extensions': [
'error',

@ -15,6 +15,11 @@ permissions:
jobs:
build-image:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v3
- uses: hadolint/hadolint-action@v3.1.0
@ -34,10 +39,11 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
type=edge,branch=main
type=sha,prefix=,format=long
- uses: docker/build-push-action@v3
- uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
provenance: false
builder: ${{ steps.buildx.outputs.name }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}

@ -30,7 +30,7 @@ jobs:
- name: Check locale file normalization
run: bundle exec i18n-tasks check-normalized
- name: Check for unused strings
run: bundle exec i18n-tasks unused -l en
run: bundle exec i18n-tasks unused
- name: Check for wrong string interpolations
run: bundle exec i18n-tasks check-consistent-interpolations
- name: Check that all required locale files exist

@ -0,0 +1,48 @@
name: CSS Linting
on:
push:
branches-ignore:
- 'dependabot/**'
paths:
- 'package.json'
- 'yarn.lock'
- '.prettier*'
- 'stylelint.config.js'
- '**/*.css'
- '**/*.scss'
- '.github/workflows/lint-css.yml'
- '.github/stylelint-matcher.json'
pull_request:
paths:
- 'package.json'
- 'yarn.lock'
- '.prettier*'
- 'stylelint.config.js'
- '**/*.css'
- '**/*.scss'
- '.github/workflows/lint-css.yml'
- '.github/stylelint-matcher.json'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
- name: Install all yarn packages
run: yarn --frozen-lockfile
- uses: xt0rted/stylelint-problem-matcher@v1
- run: echo "::add-matcher::.github/stylelint-matcher.json"
- name: Stylelint
run: yarn test:lint:sass

@ -0,0 +1,40 @@
name: JavaScript Linting
on:
push:
branches-ignore:
- 'dependabot/**'
paths:
- 'package.json'
- 'yarn.lock'
- '.prettier*'
- '.eslint*'
- '**/*.js'
- '.github/workflows/lint-js.yml'
pull_request:
paths:
- 'package.json'
- 'yarn.lock'
- '.prettier*'
- '.eslint*'
- '**/*.js'
- '.github/workflows/lint-js.yml'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: ESLint
run: yarn test:lint:js

@ -9,6 +9,7 @@ on:
- '.prettier*'
- '**/*.json'
- '.github/workflows/lint-json.yml'
- '!app/javascript/mastodon/locales/*.json'
pull_request:
paths:
@ -17,6 +18,7 @@ on:
- '.prettier*'
- '**/*.json'
- '.github/workflows/lint-json.yml'
- '!app/javascript/mastodon/locales/*.json'
jobs:
lint:

@ -0,0 +1,41 @@
name: Ruby Linting
on:
push:
branches-ignore:
- 'dependabot/**'
paths:
- 'Gemfile*'
- '.rubocop.yml'
- '**/*.rb'
- '**/*.rake'
- '.github/workflows/lint-ruby.yml'
pull_request:
paths:
- 'Gemfile*'
- '.rubocop.yml'
- '**/*.rb'
- '**/*.rake'
- '.github/workflows/lint-ruby.yml'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set-up RuboCop Problem Mathcher
uses: r7kamura/rubocop-problem-matchers-action@v1
- name: Run rubocop
uses: github/super-linter@v4
env:
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
LINTER_RULES_PATH: .
RUBY_CONFIG_FILE: .rubocop.yml
VALIDATE_ALL_CODEBASE: false
VALIDATE_RUBY: true

@ -10,6 +10,7 @@ on:
- '**/*.yaml'
- '**/*.yml'
- '.github/workflows/lint-yml.yml'
- '!config/locales/*.yml'
pull_request:
paths:
@ -19,6 +20,7 @@ on:
- '**/*.yaml'
- '**/*.yml'
- '.github/workflows/lint-yml.yml'
- '!config/locales/*.yml'
jobs:
lint:

@ -1,83 +0,0 @@
---
#################################
#################################
## Super Linter GitHub Actions ##
#################################
#################################
name: Lint Code Base
#
# Documentation:
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
#
#############################
# Start the job on all push #
#############################
on:
push:
branches-ignore: [main]
# Remove the line above to run when pushing to master
pull_request:
branches: [main]
###############
# Set the Job #
###############
permissions:
checks: write
contents: read
pull-requests: write
statuses: write
jobs:
build:
# Name the Job
name: Lint Code Base
# Set the agent to run on
runs-on: ubuntu-latest
##################
# Load all steps #
##################
steps:
##########################
# Checkout the code base #
##########################
- name: Checkout Code
uses: actions/checkout@v3
with:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
- name: Set-up Node.js
uses: actions/setup-node@v3
with:
node-version-file: .nvmrc
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Set-up RuboCop Problem Mathcher
uses: r7kamura/rubocop-problem-matchers-action@v1
- name: Set-up Stylelint Problem Matcher
uses: xt0rted/stylelint-problem-matcher@v1
# https://github.com/xt0rted/stylelint-problem-matcher/issues/360
- run: echo "::add-matcher::.github/stylelint-matcher.json"
################################
# Run Linter against code base #
################################
- name: Lint Code Base
uses: github/super-linter@v4
env:
CSS_FILE_NAME: stylelint.config.js
DEFAULT_BRANCH: main
NO_COLOR: 1 # https://github.com/xt0rted/stylelint-problem-matcher/issues/360
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JAVASCRIPT_ES_CONFIG_FILE: .eslintrc.js
LINTER_RULES_PATH: .
RUBY_CONFIG_FILE: .rubocop.yml
VALIDATE_ALL_CODEBASE: false
VALIDATE_CSS: true
VALIDATE_JAVASCRIPT_ES: true
VALIDATE_RUBY: true

@ -3,19 +3,27 @@ Changelog
All notable changes to this project will be documented in this file.
## [4.1.0] - UNRELEASED
## [4.1.0] - 2023-02-10
### Added
- **Add support for importing/exporting server-wide domain blocks** ([enbylenore](https://github.com/mastodon/mastodon/pull/20597), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/21471), [dariusk](https://github.com/mastodon/mastodon/pull/22803), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/21470))
- Add listing of followed hashtags ([connorshea](https://github.com/mastodon/mastodon/pull/21773))
- Add support for editing media description and focus point of already-sent posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20878))
- Add follow request banner on account header ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20785))
- Add confirmation screen when handling reports ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22375), [Gargron](https://github.com/mastodon/mastodon/pull/23156), [tribela](https://github.com/mastodon/mastodon/pull/23178))
- **Add listing of followed hashtags** ([connorshea](https://github.com/mastodon/mastodon/pull/21773))
- **Add support for editing media description and focus point of already-sent posts** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20878))
- Previously, you could add and remove attachments, but not edit media description of already-attached media
- REST API changes:
- `PUT /api/v1/statuses/:id` now takes an extra `media_attributes[]` array parameter with the `id` of the updated media and their updated `description`, `focus`, and `thumbnail`
- **Add follow request banner on account header** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20785))
- REST API changes:
- `Relationship` entities have an extra `requested_by` boolean attribute representing whether the represented user has requested to follow you
- **Add confirmation screen when handling reports** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22375), [Gargron](https://github.com/mastodon/mastodon/pull/23156), [tribela](https://github.com/mastodon/mastodon/pull/23178))
- Add option to make the landing page be `/about` even when trends are enabled ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20808))
- Add `noindex` setting back to the admin interface ([prplecake](https://github.com/mastodon/mastodon/pull/22205))
- Add instance peers API endpoint toggle back to the admin interface ([dariusk](https://github.com/mastodon/mastodon/pull/22810))
- Add instance activity API endpoint toggle back to the admin interface ([dariusk](https://github.com/mastodon/mastodon/pull/22833))
- Add setting for status page URL ([Gargron](https://github.com/mastodon/mastodon/pull/23390), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/23499))
- REST API changes:
- Add `configuration.urls.status` attribute to the object returned by `GET /api/v1/instance`
- Add `account.approved` webhook ([Saiv46](https://github.com/mastodon/mastodon/pull/22938))
- Add 12 hours option to polls ([Pleclown](https://github.com/mastodon/mastodon/pull/21131))
- Add dropdown menu item to open admin interface for remote domains ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21895))
@ -25,6 +33,7 @@ All notable changes to this project will be documented in this file.
- Add `tootctl accounts prune` ([tribela](https://github.com/mastodon/mastodon/pull/18397))
- Add `tootctl domains purge` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22063))
- Add `SIDEKIQ_CONCURRENCY` environment variable ([muffinista](https://github.com/mastodon/mastodon/pull/19589))
- Add `DB_POOL` environment variable support for streaming server ([Gargron](https://github.com/mastodon/mastodon/pull/23470))
- Add `MIN_THREADS` environment variable to set minimum Puma threads ([jimeh](https://github.com/mastodon/mastodon/pull/21048))
- Add explanation text to log-in page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20946))
- Add user profile OpenGraph tag on post pages ([bramus](https://github.com/mastodon/mastodon/pull/21423))
@ -38,11 +47,15 @@ All notable changes to this project will be documented in this file.
- Add brotli compression to `assets:precompile` ([Izorkin](https://github.com/mastodon/mastodon/pull/19025))
- Add “disabled” account filter to the `/admin/accounts` UI ([tribela](https://github.com/mastodon/mastodon/pull/21282))
- Add transparency to modal background for accessibility ([edent](https://github.com/mastodon/mastodon/pull/18081))
- Add `lang` attribute to image description textarea and poll option field ([c960657](https://github.com/mastodon/mastodon/pull/23293))
- Add `spellcheck` attribute to Content Warning and poll option input fields ([c960657](https://github.com/mastodon/mastodon/pull/23395))
- Add `title` attribute to video elements in media attachments ([bramus](https://github.com/mastodon/mastodon/pull/21420))
- Add left and right margins to emojis ([dsblank](https://github.com/mastodon/mastodon/pull/20464))
- Add `roles` attribute to `Account` entities in REST API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23255), [tribela](https://github.com/mastodon/mastodon/pull/23428))
- Add `reading:autoplay:gifs` to `/api/v1/preferences` ([j-f1](https://github.com/mastodon/mastodon/pull/22706))
- Add `hide_collections` parameter to `/api/v1/accounts/credentials` ([CarlSchwan](https://github.com/mastodon/mastodon/pull/22790))
- Add `policy` attribute to web push subscription objects in `/api/v1/push/subscriptions` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23210))
- Add `policy` attribute to web push subscription objects in REST API at `/api/v1/push/subscriptions` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23210))
- Add metrics endpoint to streaming API ([Gargron](https://github.com/mastodon/mastodon/pull/23388), [Gargron](https://github.com/mastodon/mastodon/pull/23469))
- Add more specific error messages to HTTP signature verification ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21617))
- Add Storj DCS to cloud object storage options in the `mastodon:setup` rake task ([jtolio](https://github.com/mastodon/mastodon/pull/21929))
- Add checkmark symbol in the checkbox for sensitive media ([sidp](https://github.com/mastodon/mastodon/pull/22795))
@ -67,8 +80,13 @@ All notable changes to this project will be documented in this file.
- Change confirm prompts for relationships management ([tribela](https://github.com/mastodon/mastodon/pull/19411))
- Change language surrounding disability in prompts for media descriptions ([hs4man21](https://github.com/mastodon/mastodon/pull/20923))
- Change confusing wording in the sign in banner ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22490))
- Change `POST /settings/applications/:id` to regenerate token on scopes change ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23359))
- Change account moderation notes to make links clickable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22553))
- Change link previews for statuses to never use avatar as fallback ([Gargron](https://github.com/mastodon/mastodon/pull/23376))
- Change email address input to be read-only for logged-in users when requesting a new confirmation e-mail ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23247))
- Change notifications per page from 15 to 40 in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/23348))
- Change number of stored items in home feed from 400 to 800 ([Gargron](https://github.com/mastodon/mastodon/pull/23349))
- Change API rate limits from 300/5min per user to 1500/5min per user, 300/5min per app ([Gargron](https://github.com/mastodon/mastodon/pull/23347))
- Save avatar or header correctly even if the other one fails ([tribela](https://github.com/mastodon/mastodon/pull/18465))
- Change `referrer-policy` to `same-origin` application-wide ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23014), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/23037))
- Add 'private' to `Cache-Control`, match Rails expectations ([daxtens](https://github.com/mastodon/mastodon/pull/20608))
@ -88,7 +106,7 @@ All notable changes to this project will be documented in this file.
- Allow adding relays in secure mode and limited federation mode ([ineffyble](https://github.com/mastodon/mastodon/pull/22324))
- Change timestamps to be displayed using the user's timezone throughout the moderation interface ([FrancisMurillo](https://github.com/mastodon/mastodon/pull/21878), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/22555))
- Change CSP directives on API to be tight and concise ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20960))
- Change web UI to not autofocus the compose form ([raboof](https://github.com/mastodon/mastodon/pull/16517))
- Change web UI to not autofocus the compose form ([raboof](https://github.com/mastodon/mastodon/pull/16517), [Akkiesoft](https://github.com/mastodon/mastodon/pull/23094))
- Change idempotency key handling for posting when database access is slow ([lambda](https://github.com/mastodon/mastodon/pull/21840))
- Change remote media files to be downloaded outside of transactions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21796))
- Improve contrast of charts in “poll has ended” notifications ([j-f1](https://github.com/mastodon/mastodon/pull/22575))
@ -101,31 +119,38 @@ All notable changes to this project will be documented in this file.
- Officially remove support for Ruby 2.6 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21477))
- Remove `object-fit` polyfill used for old versions of Microsoft Edge ([shuuji3](https://github.com/mastodon/mastodon/pull/22693))
- Remove `intersection-observer` polyfill for old Safari support ([shuuji3](https://github.com/mastodon/mastodon/pull/23284))
- Remove empty `title` tag from mailer layout ([nametoolong](https://github.com/mastodon/mastodon/pull/23078))
- Remove post count and last posts from ActivityPub representation of hashtag collections ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23460))
### Fixed
- **Fix changing domain block severity not undoing individual account effects** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22135))
- Fix suspension worker crashing on S3-compatible setups without ACL support ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22487))
- Fix possible race conditions when suspending/unsuspending accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22363))
- Fix being stuck in edit mode when deleting the edited status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22126))
- Fix being stuck in edit mode when deleting the edited posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22126))
- Fix attached media uploads not being cleared when replying to a post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23504))
- Fix filters not being applied to some notification types ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23211))
- Fix incorrect link in push notifications for some event types ([elizabeth-dev](https://github.com/mastodon/mastodon/pull/23286))
- Fix some performance issues with `/admin/instances` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21907))
- Fix some pre-4.0 admin audit logs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22091))
- Fix moderation audit log items for warnings having incorrect links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23242))
- Fix account activation being sometimes triggered before email confirmation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23245))
- Fix missing OAuth scopes for admin APIs ([trwnh](https://github.com/mastodon/mastodon/pull/20918), [trwnh](https://github.com/mastodon/mastodon/pull/20979))
- Fix voter count not being cleared when a poll is reset ([afontenot](https://github.com/mastodon/mastodon/pull/21700))
- Fix attachments of edited statuses not being fetched ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21565))
- Fix attachments of edited posts not being fetched ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21565))
- Fix irreversible and whole_word parameters handling in `/api/v1/filters` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21988))
- Fix 500 error when marking posts as sensitive while some of them are deleted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22134))
- Fix expanded statuses not always being scrolled into view ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21797))
- Fix expanded posts not always being scrolled into view ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21797))
- Fix not being able to scroll the remote interaction modal on small screens ([xendke](https://github.com/mastodon/mastodon/pull/21763))
- Fix not being able to scroll in post history modal ([cadars](https://github.com/mastodon/mastodon/pull/23396))
- Fix audio player volume control on Safari ([minacle](https://github.com/mastodon/mastodon/pull/23187))
- Fix disappearing “Explore” tabs on Safari ([nyura](https://github.com/mastodon/mastodon/pull/20917), [ykzts](https://github.com/mastodon/mastodon/pull/20982))
- Fix wrong padding in RTL layout ([Gargron](https://github.com/mastodon/mastodon/pull/23157))
- Fix drag & drop upload area display in single-column mode ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23217))
- Fix being unable to get a single EmailDomainBlock from the admin API ([trwnh](https://github.com/mastodon/mastodon/pull/20846))
- Fix admin-set follow recommandations being case-sensitive ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23500))
- Fix unserialized `role` on account entities in admin API ([Gargron](https://github.com/mastodon/mastodon/pull/23290))
- Fix pagination of followed tags ([trwnh](https://github.com/mastodon/mastodon/pull/20861))
- Fix dropdown menu positions when scrolling ([sidp](https://github.com/mastodon/mastodon/pull/22916), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/23062))
- Fix email with empty domain name labels passing validation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23246))
@ -136,9 +161,11 @@ All notable changes to this project will be documented in this file.
- Fix error in `VerifyLinkService` when processing links with invalid URLs ([untitaker](https://github.com/mastodon/mastodon/pull/23204))
- Fix media uploads with FFmpeg 5 ([dead10ck](https://github.com/mastodon/mastodon/pull/21191))
- Fix sensitive flag not being set when replying to a post with a content warning under certain conditions ([kedamaDQ](https://github.com/mastodon/mastodon/pull/21724))
- Fix “Share @user's profile” profile menu item not working ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21490))
- Fix misleading message briefly showing up when loading follow requests under some conditions ([c960657](https://github.com/mastodon/mastodon/pull/23386))
- Fix “Share @:user's profile” profile menu item not working ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21490))
- Fix crash and incorrect behavior in `tootctl domains crawl` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19004))
- Fix autoplay on iOS ([jamesadney](https://github.com/mastodon/mastodon/pull/21422))
- Fix user clean-up scheduler crash when an unconfirmed account has a moderation note ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23318))
- Fix spaces not being stripped in admin account search ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21324))
- Fix spaces not being stripped when adding relays ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22655))
- Fix infinite loading spinner instead of soft 404 for non-existing remote accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21303))
@ -148,8 +175,10 @@ All notable changes to this project will be documented in this file.
- Fix UI header overflowing on mobile ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21783))
- Fix 500 error when trying to migrate to an invalid address ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21462))
- Fix crash when trying to fetch unobtainable avatar of user using external authentication ([lochiiconnectivity](https://github.com/mastodon/mastodon/pull/22462))
- Fix potential duplicate statuses in Explore tab ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22121))
- Fix processing error on incoming malformed JSON-LD under some situations ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23416))
- Fix potential duplicate posts in Explore tab ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22121))
- Fix deprecation warning in `tootctl accounts rotate` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22120))
- Fix styling of featured tags in light theme ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23252))
- Fix missing style in warning and strike cards ([AtelierSnek](https://github.com/mastodon/mastodon/pull/22177), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/22302))
- Fix wasteful request to `/api/v1/custom_emojis` when not logged in ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22326))
- Fix replies sometimes being delivered to user-blocked domains ([tribela](https://github.com/mastodon/mastodon/pull/22117))
@ -167,7 +196,7 @@ All notable changes to this project will be documented in this file.
- Fix CSP violation warning by removing inline CSS from SVG logo ([luxiaba](https://github.com/mastodon/mastodon/pull/20814))
- Fix margin for search field on medium window size ([minacle](https://github.com/mastodon/mastodon/pull/21606))
- Fix search popout scrolling with the page in single-column mode ([rgroothuijsen](https://github.com/mastodon/mastodon/pull/16463))
- Fix minor status cache hydration discrepancy ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19879))
- Fix minor post cache hydration discrepancy ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/19879))
- Fix `・` detection in hashtags ([parthoghosh24](https://github.com/mastodon/mastodon/pull/22888))
- Fix hashtag follows bypassing user blocks ([tribela](https://github.com/mastodon/mastodon/pull/22849))
- Fix moved accounts being incorrectly redirected to account settings when trying to view a remote profile ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22497))
@ -187,6 +216,7 @@ All notable changes to this project will be documented in this file.
- Add `form-action` CSP directive ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/20781), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/20958), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/20962))
- Fix unbounded recursion in account discovery ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/22025))
- Revoke all authorized applications on password reset ([FrancisMurillo](https://github.com/mastodon/mastodon/pull/21325))
- Fix unbounded recursion in post discovery ([ClearlyClaire,nametoolong](https://github.com/mastodon/mastodon/pull/23506))
## [4.0.2] - 2022-11-15
### Fixed

@ -18,7 +18,7 @@ gem 'makara', '~> 0.5'
gem 'pghero'
gem 'dotenv-rails', '~> 2.8'
gem 'aws-sdk-s3', '~> 1.117', require: false
gem 'aws-sdk-s3', '~> 1.119', require: false
gem 'fog-core', '<= 2.4.0'
gem 'fog-openstack', '~> 0.3', require: false
gem 'kt-paperclip', '~> 7.1'
@ -26,7 +26,7 @@ gem 'blurhash', '~> 0.1'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
gem 'bootsnap', '~> 1.15.0', require: false
gem 'bootsnap', '~> 1.16.0', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.2'
@ -40,7 +40,7 @@ end
gem 'net-ldap', '~> 0.17'
gem 'omniauth-cas', '~> 2.0'
gem 'omniauth-saml', '~> 1.10'
gem 'gitlab-omniauth-openid-connect', '~>0.10.0', require: 'omniauth_openid_connect'
gem 'gitlab-omniauth-openid-connect', '~>0.10.1', require: 'omniauth_openid_connect'
gem 'omniauth', '~> 1.9'
gem 'omniauth-rails_csrf_protection', '~> 0.1'
@ -73,7 +73,7 @@ gem 'rack-attack', '~> 6.6'
gem 'rack-cors', '~> 1.1', require: 'rack/cors'
gem 'rails-i18n', '~> 6.0'
gem 'rails-settings-cached', '~> 0.6'
gem 'redcarpet', '~> 3.5'
gem 'redcarpet', '~> 3.6'
gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 2.1'
@ -85,7 +85,7 @@ gem 'sidekiq-scheduler', '~> 4.0'
gem 'sidekiq-unique-jobs', '~> 7.1'
gem 'sidekiq-bulk', '~> 0.2.0'
gem 'simple-navigation', '~> 4.4'
gem 'simple_form', '~> 5.1'
gem 'simple_form', '~> 5.2'
gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie'
gem 'stoplight', '~> 3.0.1'
gem 'strong_migrations', '~> 0.7'

@ -10,40 +10,40 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (6.1.7.1)
actionpack (= 6.1.7.1)
activesupport (= 6.1.7.1)
actioncable (6.1.7.2)
actionpack (= 6.1.7.2)
activesupport (= 6.1.7.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.1.7.1)
actionpack (= 6.1.7.1)
activejob (= 6.1.7.1)
activerecord (= 6.1.7.1)
activestorage (= 6.1.7.1)
activesupport (= 6.1.7.1)
actionmailbox (6.1.7.2)
actionpack (= 6.1.7.2)
activejob (= 6.1.7.2)
activerecord (= 6.1.7.2)
activestorage (= 6.1.7.2)
activesupport (= 6.1.7.2)
mail (>= 2.7.1)
actionmailer (6.1.7.1)
actionpack (= 6.1.7.1)
actionview (= 6.1.7.1)
activejob (= 6.1.7.1)
activesupport (= 6.1.7.1)
actionmailer (6.1.7.2)
actionpack (= 6.1.7.2)
actionview (= 6.1.7.2)
activejob (= 6.1.7.2)
activesupport (= 6.1.7.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.7.1)
actionview (= 6.1.7.1)
activesupport (= 6.1.7.1)
actionpack (6.1.7.2)
actionview (= 6.1.7.2)
activesupport (= 6.1.7.2)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.1.7.1)
actionpack (= 6.1.7.1)
activerecord (= 6.1.7.1)
activestorage (= 6.1.7.1)
activesupport (= 6.1.7.1)
actiontext (6.1.7.2)
actionpack (= 6.1.7.2)
activerecord (= 6.1.7.2)
activestorage (= 6.1.7.2)
activesupport (= 6.1.7.2)
nokogiri (>= 1.8.5)
actionview (6.1.7.1)
activesupport (= 6.1.7.1)
actionview (6.1.7.2)
activesupport (= 6.1.7.2)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
@ -54,22 +54,22 @@ GEM
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
active_record_query_trace (1.8)
activejob (6.1.7.1)
activesupport (= 6.1.7.1)
activejob (6.1.7.2)
activesupport (= 6.1.7.2)
globalid (>= 0.3.6)
activemodel (6.1.7.1)
activesupport (= 6.1.7.1)
activerecord (6.1.7.1)
activemodel (= 6.1.7.1)
activesupport (= 6.1.7.1)
activestorage (6.1.7.1)
actionpack (= 6.1.7.1)
activejob (= 6.1.7.1)
activerecord (= 6.1.7.1)
activesupport (= 6.1.7.1)
activemodel (6.1.7.2)
activesupport (= 6.1.7.2)
activerecord (6.1.7.2)
activemodel (= 6.1.7.2)
activesupport (= 6.1.7.2)
activestorage (6.1.7.2)
actionpack (= 6.1.7.2)
activejob (= 6.1.7.2)
activerecord (= 6.1.7.2)
activesupport (= 6.1.7.2)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
activesupport (6.1.7.1)
activesupport (6.1.7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@ -90,16 +90,16 @@ GEM
attr_required (1.0.1)
awrence (1.2.1)
aws-eventstream (1.2.0)
aws-partitions (1.670.0)
aws-sdk-core (3.168.2)
aws-partitions (1.701.0)
aws-sdk-core (3.170.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.60.0)
aws-sdk-kms (1.62.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.117.2)
aws-sdk-s3 (1.119.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@ -117,12 +117,12 @@ GEM
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
bindata (2.4.10)
bindata (2.4.14)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
blurhash (0.1.6)
ffi (~> 1.14)
bootsnap (1.15.0)
bootsnap (1.16.0)
msgpack (~> 1.2)
brakeman (5.4.0)
browser (4.2.0)
@ -207,7 +207,7 @@ GEM
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.6.2)
doorkeeper (5.6.4)
railties (>= 5)
dotenv (2.8.1)
dotenv-rails (2.8.1)
@ -229,7 +229,7 @@ GEM
tzinfo
excon (0.95.0)
fabrication (2.30.0)
faker (3.1.0)
faker (3.1.1)
i18n (>= 1.8.11, < 2)
faraday (1.9.3)
faraday-em_http (~> 1.0)
@ -279,11 +279,11 @@ GEM
fuubar (2.5.1)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
gitlab-omniauth-openid-connect (0.10.0)
gitlab-omniauth-openid-connect (0.10.1)
addressable (~> 2.7)
omniauth (>= 1.9, < 3)
openid_connect (~> 1.2)
globalid (1.0.1)
globalid (1.1.0)
activesupport (>= 5.0)
hamlit (2.13.0)
temple (>= 0.8.2)
@ -333,10 +333,11 @@ GEM
jmespath (1.6.2)
json (2.6.3)
json-canonicalization (0.3.0)
json-jwt (1.14.0)
json-jwt (1.15.3)
activesupport (>= 4.2)
aes_key_wrap
bindata
httpclient
json-ld (3.2.3)
htmlentities (~> 4.3)
json-canonicalization (~> 0.3)
@ -418,7 +419,7 @@ GEM
net-ldap (0.17.1)
net-pop (0.1.2)
net-protocol
net-protocol (0.1.3)
net-protocol (0.2.1)
timeout
net-scp (4.0.0.rc1)
net-ssh (>= 2.6.5, < 8.0.0)
@ -426,7 +427,7 @@ GEM
net-protocol
net-ssh (7.0.1)
nio4r (2.5.8)
nokogiri (1.14.0)
nokogiri (1.14.1)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nsa (0.2.8)
@ -448,21 +449,22 @@ GEM
omniauth-saml (1.10.3)
omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.9)
openid_connect (1.3.0)
openid_connect (1.4.2)
activemodel
attr_required (>= 1.0.0)
json-jwt (>= 1.5.0)
rack-oauth2 (>= 1.6.1)
swd (>= 1.0.0)
json-jwt (>= 1.15.0)
net-smtp
rack-oauth2 (~> 1.21)
swd (~> 1.3)
tzinfo
validate_email
validate_url
webfinger (>= 1.0.1)
webfinger (~> 1.2)
openssl (3.0.0)
openssl-signature_algorithm (1.2.1)
openssl (> 2.0, < 3.1)
orm_adapter (0.5.0)
ox (2.14.13)
ox (2.14.14)
parallel (1.22.1)
parser (3.2.0.0)
ast (~> 2.4.1)
@ -503,30 +505,30 @@ GEM
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack (>= 2.0.0)
rack-oauth2 (1.19.0)
rack-oauth2 (1.21.3)
activesupport
attr_required
httpclient
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-proxy (0.7.0)
rack-proxy (0.7.6)
rack
rack-test (2.0.2)
rack (>= 1.3)
rails (6.1.7.1)
actioncable (= 6.1.7.1)
actionmailbox (= 6.1.7.1)
actionmailer (= 6.1.7.1)
actionpack (= 6.1.7.1)
actiontext (= 6.1.7.1)
actionview (= 6.1.7.1)
activejob (= 6.1.7.1)
activemodel (= 6.1.7.1)
activerecord (= 6.1.7.1)
activestorage (= 6.1.7.1)
activesupport (= 6.1.7.1)
rails (6.1.7.2)
actioncable (= 6.1.7.2)
actionmailbox (= 6.1.7.2)
actionmailer (= 6.1.7.2)
actionpack (= 6.1.7.2)
actiontext (= 6.1.7.2)
actionview (= 6.1.7.2)
activejob (= 6.1.7.2)
activemodel (= 6.1.7.2)
activerecord (= 6.1.7.2)
activestorage (= 6.1.7.2)
activesupport (= 6.1.7.2)
bundler (>= 1.15.0)
railties (= 6.1.7.1)
railties (= 6.1.7.2)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
@ -535,16 +537,16 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.4.4)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
rails-i18n (6.0.0)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 7)
rails-settings-cached (0.6.6)
rails (>= 4.2.0)
railties (6.1.7.1)
actionpack (= 6.1.7.1)
activesupport (= 6.1.7.1)
railties (6.1.7.2)
actionpack (= 6.1.7.2)
activesupport (= 6.1.7.2)
method_source
rake (>= 12.2)
thor (~> 1.0)
@ -554,7 +556,7 @@ GEM
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.5.1)
rdf (~> 3.2)
redcarpet (3.5.1)
redcarpet (3.6.0)
redis (4.5.1)
redis-namespace (1.10.0)
redis (>= 4)
@ -595,7 +597,7 @@ GEM
rspec-support (3.11.1)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.44.0)
rubocop (1.44.1)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)
@ -609,7 +611,7 @@ GEM
parser (>= 3.1.1.0)
rubocop-capybara (2.17.0)
rubocop (~> 1.41)
rubocop-performance (1.15.2)
rubocop-performance (1.16.0)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.17.4)
@ -628,7 +630,7 @@ GEM
fugit (~> 1.1, >= 1.1.6)
safety_net_attestation (0.4.0)
jwt (~> 2.0)
sanitize (6.0.0)
sanitize (6.0.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
scenic (1.7.0)
@ -654,7 +656,7 @@ GEM
thor (>= 0.20, < 3.0)
simple-navigation (4.4.0)
activesupport (>= 2.3.2)
simple_form (5.1.0)
simple_form (5.2.0)
actionpack (>= 5.2)
activemodel (>= 5.2)
simplecov (0.22.0)
@ -691,7 +693,7 @@ GEM
climate_control (>= 0.0.3, < 1.0)
thor (1.2.1)
tilt (2.0.11)
timeout (0.3.0)
timeout (0.3.1)
tpm-key_attestation (0.11.0)
bindata (~> 2.4)
openssl (> 2.0, < 3.1)
@ -709,7 +711,7 @@ GEM
twitter-text (3.1.0)
idn-ruby
unf (~> 0.1.0)
tzinfo (2.0.5)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2022.7)
tzinfo (>= 1.0.0)
@ -742,7 +744,7 @@ GEM
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.4.3)
webpacker (5.4.4)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
@ -764,11 +766,11 @@ DEPENDENCIES
active_record_query_trace (~> 1.8)
addressable (~> 2.8)
annotate (~> 3.2)
aws-sdk-s3 (~> 1.117)
aws-sdk-s3 (~> 1.119)
better_errors (~> 2.9)
binding_of_caller (~> 1.0)
blurhash (~> 0.1)
bootsnap (~> 1.15.0)
bootsnap (~> 1.16.0)
brakeman (~> 5.4)
browser
bullet (~> 7.0)
@ -799,7 +801,7 @@ DEPENDENCIES
fog-core (<= 2.4.0)
fog-openstack (~> 0.3)
fuubar (~> 2.5)
gitlab-omniauth-openid-connect (~> 0.10.0)
gitlab-omniauth-openid-connect (~> 0.10.1)
hamlit-rails (~> 0.2)
hcaptcha (~> 7.1)
hiredis (~> 0.6)
@ -852,7 +854,7 @@ DEPENDENCIES
rails-i18n (~> 6.0)
rails-settings-cached (~> 0.6)
rdf-normalize (~> 0.5)
redcarpet (~> 3.5)
redcarpet (~> 3.6)
redis (~> 4.5)
redis-namespace (~> 1.10)
rexml (~> 3.2)
@ -872,7 +874,7 @@ DEPENDENCIES
sidekiq-scheduler (~> 4.0)
sidekiq-unique-jobs (~> 7.1)
simple-navigation (~> 4.4)
simple_form (~> 5.1)
simple_form (~> 5.2)
simplecov (~> 0.22)
sprockets (~> 3.7.2)
sprockets-rails (~> 3.4)

@ -6,7 +6,7 @@ class Api::V1::NotificationsController < Api::BaseController
before_action :require_user!
after_action :insert_pagination_headers, only: :index
DEFAULT_NOTIFICATIONS_LIMIT = 15
DEFAULT_NOTIFICATIONS_LIMIT = 40
def index
@notifications = load_notifications

@ -2,10 +2,10 @@
class Api::V1::StreamingController < Api::BaseController
def index
if Rails.configuration.x.streaming_api_base_url != request.host
redirect_to streaming_api_url, status: 301
else
if Rails.configuration.x.streaming_api_base_url == request.host
not_found
else
redirect_to streaming_api_url, status: 301
end
end

@ -227,7 +227,7 @@ module SignatureVerification
end
def to_header_name(name)
name.split(/-/).map(&:capitalize).join('-')
name.split('-').map(&:capitalize).join('-')
end
def missing_required_signature_parameters?

@ -29,7 +29,13 @@ class Settings::ApplicationsController < Settings::BaseController
def update
if @application.update(application_params)
redirect_to settings_applications_path, notice: I18n.t('generic.changes_saved_msg')
if @application.scopes_previously_changed?
@access_token = current_user.token_for_app(@application)
@access_token.destroy
redirect_to settings_application_path(@application), notice: I18n.t('applications.token_regenerated')
else
redirect_to settings_application_path(@application), notice: I18n.t('generic.changes_saved_msg')
end
else
render :show
end

@ -11,7 +11,7 @@ class TagsController < ApplicationController
before_action :authenticate_user!, if: :whitelist_mode?
before_action :set_local
before_action :set_tag
before_action :set_statuses
before_action :set_statuses, if: -> { request.format == :rss }
before_action :set_instance_presenter
skip_before_action :require_functional!, unless: :whitelist_mode?
@ -44,12 +44,7 @@ class TagsController < ApplicationController
end
def set_statuses
case request.format&.to_sym
when :json
@statuses = cache_collection(TagFeed.new(@tag, current_account, local: @local).get(PAGE_SIZE, params[:max_id], params[:since_id], params[:min_id]), Status)
when :rss
@statuses = cache_collection(TagFeed.new(@tag, nil, local: @local).get(limit_param), Status)
end
@statuses = cache_collection(TagFeed.new(@tag, nil, local: @local).get(limit_param), Status)
end
def set_instance_presenter
@ -64,8 +59,6 @@ class TagsController < ApplicationController
ActivityPub::CollectionPresenter.new(
id: tag_url(@tag),
type: :ordered,
size: @tag.statuses.count,
items: @statuses.map { |status| ActivityPub::TagManager.instance.uri_for(status) }
)
end
end

@ -67,7 +67,7 @@ module ApplicationHelper
def link_to_login(name = nil, html_options = nil, &block)
target = new_user_session_path
html_options = name if block_given?
html_options = name if block
if omniauth_only? && Devise.mappings[:user].omniauthable? && User.omniauth_providers.size == 1
target = omniauth_authorize_path(:user, User.omniauth_providers[0])
@ -75,7 +75,7 @@ module ApplicationHelper
html_options[:method] = :post
end
if block_given?
if block
link_to(target, html_options, &block)
else
link_to(name, target, html_options)

@ -7,7 +7,7 @@ module EmailHelper
def email_to_canonical_email(str)
username, domain = str.downcase.split('@', 2)
username, = username.gsub('.', '').split('+', 2)
username, = username.delete('.').split('+', 2)
"#{username}@#{domain}"
end

@ -213,7 +213,7 @@ module JsonLdHelper
end
end
def load_jsonld_context(url, _options = {}, &_block)
def load_jsonld_context(url, _options = {}, &block)
json = Rails.cache.fetch("jsonld:context:#{url}", expires_in: 30.days, raw: true) do
request = Request.new(:get, url)
request.add_headers('Accept' => 'application/ld+json')
@ -226,6 +226,6 @@ module JsonLdHelper
doc = JSON::LD::API::RemoteDocument.new(json, documentUrl: url)
block_given? ? yield(doc) : doc
block ? yield(doc) : doc
end
end

@ -199,6 +199,8 @@ module LanguagesHelper
sco: ['Scots', 'Scots'].freeze,
sma: ['Southern Sami', 'Åarjelsaemien Gïele'].freeze,
smj: ['Lule Sami', 'Julevsámegiella'].freeze,
szl: ['Silesian', 'ślůnsko godka'].freeze,
tai: ['Tai', 'ภาษาไท or ภาษาไต'].freeze,
tok: ['Toki Pona', 'toki pona'].freeze,
zba: ['Balaibalan', 'باليبلن'].freeze,
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
@ -210,8 +212,10 @@ module LanguagesHelper
# names, but for some translations, we need the names of the
# regional variants specifically
REGIONAL_LOCALE_NAMES = {
'en-GB': 'English (British)',
'es-AR': 'Español (Argentina)',
'es-MX': 'Español (México)',
'fr-QC': 'Français (Canadien)',
'pt-BR': 'Português (Brasil)',
'pt-PT': 'Português (Portugal)',
'sr-Latn': 'Srpski (latinica)',

@ -15,7 +15,7 @@ window.addEventListener('message', e => {
id: data.id,
height: document.getElementsByTagName('html')[0].scrollHeight,
}, '*');
};
}
if (['interactive', 'complete'].includes(document.readyState)) {
setEmbedHeight();

@ -2,7 +2,9 @@
import 'packs/public-path';
import escapeTextContentForBrowser from 'escape-html';
const { delegate } = require('@rails/ujs');
import emojify from '../mastodon/features/emoji/emoji';
delegate(document, '#account_display_name', 'input', ({ target }) => {
@ -65,7 +67,7 @@ delegate(document, '.input-copy button', 'click', ({ target }) => {
input.blur();
target.parentNode.classList.add('copied');
setTimeout(() => {
setTimeout(() => {
target.parentNode.classList.remove('copied');
}, 700);
}

@ -21,27 +21,27 @@ export function submitAccountNote() {
dispatch(submitAccountNoteSuccess(response.data));
}).catch(error => dispatch(submitAccountNoteFail(error)));
};
};
}
export function submitAccountNoteRequest() {
return {
type: ACCOUNT_NOTE_SUBMIT_REQUEST,
};
};
}
export function submitAccountNoteSuccess(relationship) {
return {
type: ACCOUNT_NOTE_SUBMIT_SUCCESS,
relationship,
};
};
}
export function submitAccountNoteFail(error) {
return {
type: ACCOUNT_NOTE_SUBMIT_FAIL,
error,
};
};
}
export function initEditAccountNote(account) {
return (dispatch, getState) => {
@ -53,17 +53,17 @@ export function initEditAccountNote(account) {
comment,
});
};
};
}
export function cancelAccountNote() {
return {
type: ACCOUNT_NOTE_CANCEL,
};
};
}
export function changeAccountNoteComment(comment) {
return {
type: ACCOUNT_NOTE_CHANGE_COMMENT,
comment,
};
};
}

@ -108,7 +108,7 @@ export function fetchAccount(id) {
dispatch(fetchAccountFail(id, error));
});
};
};
}
export const lookupAccount = acct => (dispatch, getState) => {
dispatch(lookupAccountRequest(acct));
@ -143,13 +143,13 @@ export function fetchAccountRequest(id) {
type: ACCOUNT_FETCH_REQUEST,
id,
};
};
}
export function fetchAccountSuccess() {
return {
type: ACCOUNT_FETCH_SUCCESS,
};
};
}
export function fetchAccountFail(id, error) {
return {
@ -158,7 +158,7 @@ export function fetchAccountFail(id, error) {
error,
skipAlert: true,
};
};
}
export function followAccount(id, options = { reblogs: true }) {
return (dispatch, getState) => {
@ -173,7 +173,7 @@ export function followAccount(id, options = { reblogs: true }) {
dispatch(followAccountFail(error, locked));
});
};
};
}
export function unfollowAccount(id) {
return (dispatch, getState) => {
@ -185,7 +185,7 @@ export function unfollowAccount(id) {
dispatch(unfollowAccountFail(error));
});
};
};
}
export function followAccountRequest(id, locked) {
return {
@ -194,7 +194,7 @@ export function followAccountRequest(id, locked) {
locked,
skipLoading: true,
};
};
}
export function followAccountSuccess(relationship, alreadyFollowing) {
return {
@ -203,7 +203,7 @@ export function followAccountSuccess(relationship, alreadyFollowing) {
alreadyFollowing,
skipLoading: true,
};
};
}
export function followAccountFail(error, locked) {
return {
@ -212,7 +212,7 @@ export function followAccountFail(error, locked) {
locked,
skipLoading: true,
};
};
}
export function unfollowAccountRequest(id) {
return {
@ -220,7 +220,7 @@ export function unfollowAccountRequest(id) {
id,
skipLoading: true,
};
};
}
export function unfollowAccountSuccess(relationship, statuses) {
return {
@ -229,7 +229,7 @@ export function unfollowAccountSuccess(relationship, statuses) {
statuses,
skipLoading: true,
};
};
}
export function unfollowAccountFail(error) {
return {
@ -237,7 +237,7 @@ export function unfollowAccountFail(error) {
error,
skipLoading: true,
};
};
}
export function blockAccount(id) {
return (dispatch, getState) => {
@ -250,7 +250,7 @@ export function blockAccount(id) {
dispatch(blockAccountFail(id, error));
});
};
};
}
export function unblockAccount(id) {
return (dispatch, getState) => {
@ -262,14 +262,14 @@ export function unblockAccount(id) {
dispatch(unblockAccountFail(id, error));
});
};
};
}
export function blockAccountRequest(id) {
return {
type: ACCOUNT_BLOCK_REQUEST,
id,
};
};
}
export function blockAccountSuccess(relationship, statuses) {
return {
@ -277,35 +277,35 @@ export function blockAccountSuccess(relationship, statuses) {
relationship,
statuses,
};
};
}
export function blockAccountFail(error) {
return {
type: ACCOUNT_BLOCK_FAIL,
error,
};
};
}
export function unblockAccountRequest(id) {
return {
type: ACCOUNT_UNBLOCK_REQUEST,
id,
};
};
}
export function unblockAccountSuccess(relationship) {
return {
type: ACCOUNT_UNBLOCK_SUCCESS,
relationship,
};
};
}
export function unblockAccountFail(error) {
return {
type: ACCOUNT_UNBLOCK_FAIL,
error,
};
};
}
export function muteAccount(id, notifications, duration=0) {
@ -319,7 +319,7 @@ export function muteAccount(id, notifications, duration=0) {
dispatch(muteAccountFail(id, error));
});
};
};
}
export function unmuteAccount(id) {
return (dispatch, getState) => {
@ -331,14 +331,14 @@ export function unmuteAccount(id) {
dispatch(unmuteAccountFail(id, error));
});
};
};
}
export function muteAccountRequest(id) {
return {
type: ACCOUNT_MUTE_REQUEST,
id,
};
};
}
export function muteAccountSuccess(relationship, statuses) {
return {
@ -346,35 +346,35 @@ export function muteAccountSuccess(relationship, statuses) {
relationship,
statuses,
};
};
}
export function muteAccountFail(error) {
return {
type: ACCOUNT_MUTE_FAIL,
error,
};
};
}
export function unmuteAccountRequest(id) {
return {
type: ACCOUNT_UNMUTE_REQUEST,
id,
};
};
}
export function unmuteAccountSuccess(relationship) {
return {
type: ACCOUNT_UNMUTE_SUCCESS,
relationship,
};
};
}
export function unmuteAccountFail(error) {
return {
type: ACCOUNT_UNMUTE_FAIL,
error,
};
};
}
export function fetchFollowers(id) {
@ -391,14 +391,14 @@ export function fetchFollowers(id) {
dispatch(fetchFollowersFail(id, error));
});
};
};
}
export function fetchFollowersRequest(id) {
return {
type: FOLLOWERS_FETCH_REQUEST,
id,
};
};
}
export function fetchFollowersSuccess(id, accounts, next) {
return {
@ -407,7 +407,7 @@ export function fetchFollowersSuccess(id, accounts, next) {
accounts,
next,
};
};
}
export function fetchFollowersFail(id, error) {
return {
@ -416,7 +416,7 @@ export function fetchFollowersFail(id, error) {
error,
skipNotFound: true,
};
};
}
export function expandFollowers(id) {
return (dispatch, getState) => {
@ -438,14 +438,14 @@ export function expandFollowers(id) {
dispatch(expandFollowersFail(id, error));
});
};
};
}
export function expandFollowersRequest(id) {
return {
type: FOLLOWERS_EXPAND_REQUEST,
id,
};
};
}
export function expandFollowersSuccess(id, accounts, next) {
return {
@ -454,7 +454,7 @@ export function expandFollowersSuccess(id, accounts, next) {
accounts,
next,
};
};
}
export function expandFollowersFail(id, error) {
return {
@ -462,7 +462,7 @@ export function expandFollowersFail(id, error) {
id,
error,
};
};
}
export function fetchFollowing(id) {
return (dispatch, getState) => {
@ -478,14 +478,14 @@ export function fetchFollowing(id) {
dispatch(fetchFollowingFail(id, error));
});
};
};
}
export function fetchFollowingRequest(id) {
return {
type: FOLLOWING_FETCH_REQUEST,
id,
};
};
}
export function fetchFollowingSuccess(id, accounts, next) {
return {
@ -494,7 +494,7 @@ export function fetchFollowingSuccess(id, accounts, next) {
accounts,
next,
};
};
}
export function fetchFollowingFail(id, error) {
return {
@ -503,7 +503,7 @@ export function fetchFollowingFail(id, error) {
error,
skipNotFound: true,
};
};
}
export function expandFollowing(id) {
return (dispatch, getState) => {
@ -525,14 +525,14 @@ export function expandFollowing(id) {
dispatch(expandFollowingFail(id, error));
});
};
};
}
export function expandFollowingRequest(id) {
return {
type: FOLLOWING_EXPAND_REQUEST,
id,
};
};
}
export function expandFollowingSuccess(id, accounts, next) {
return {
@ -541,7 +541,7 @@ export function expandFollowingSuccess(id, accounts, next) {
accounts,
next,
};
};
}
export function expandFollowingFail(id, error) {
return {
@ -549,7 +549,7 @@ export function expandFollowingFail(id, error) {
id,
error,
};
};
}
export function fetchRelationships(accountIds) {
return (dispatch, getState) => {
@ -570,7 +570,7 @@ export function fetchRelationships(accountIds) {
dispatch(fetchRelationshipsFail(error));
});
};
};
}
export function fetchRelationshipsRequest(ids) {
return {
@ -578,7 +578,7 @@ export function fetchRelationshipsRequest(ids) {
ids,
skipLoading: true,
};
};
}
export function fetchRelationshipsSuccess(relationships) {
return {
@ -586,7 +586,7 @@ export function fetchRelationshipsSuccess(relationships) {
relationships,
skipLoading: true,
};
};
}
export function fetchRelationshipsFail(error) {
return {
@ -595,7 +595,7 @@ export function fetchRelationshipsFail(error) {
skipLoading: true,
skipNotFound: true,
};
};
}
export function fetchFollowRequests() {
return (dispatch, getState) => {
@ -607,13 +607,13 @@ export function fetchFollowRequests() {
dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null));
}).catch(error => dispatch(fetchFollowRequestsFail(error)));
};
};
}
export function fetchFollowRequestsRequest() {
return {
type: FOLLOW_REQUESTS_FETCH_REQUEST,
};
};
}
export function fetchFollowRequestsSuccess(accounts, next) {
return {
@ -621,14 +621,14 @@ export function fetchFollowRequestsSuccess(accounts, next) {
accounts,
next,
};
};
}
export function fetchFollowRequestsFail(error) {
return {
type: FOLLOW_REQUESTS_FETCH_FAIL,
error,
};
};
}
export function expandFollowRequests() {
return (dispatch, getState) => {
@ -646,13 +646,13 @@ export function expandFollowRequests() {
dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null));
}).catch(error => dispatch(expandFollowRequestsFail(error)));
};
};
}
export function expandFollowRequestsRequest() {
return {
type: FOLLOW_REQUESTS_EXPAND_REQUEST,
};
};
}
export function expandFollowRequestsSuccess(accounts, next) {
return {
@ -660,14 +660,14 @@ export function expandFollowRequestsSuccess(accounts, next) {
accounts,
next,
};
};
}
export function expandFollowRequestsFail(error) {
return {
type: FOLLOW_REQUESTS_EXPAND_FAIL,
error,
};
};
}
export function authorizeFollowRequest(id) {
return (dispatch, getState) => {
@ -678,21 +678,21 @@ export function authorizeFollowRequest(id) {
.then(() => dispatch(authorizeFollowRequestSuccess(id)))
.catch(error => dispatch(authorizeFollowRequestFail(id, error)));
};
};
}
export function authorizeFollowRequestRequest(id) {
return {
type: FOLLOW_REQUEST_AUTHORIZE_REQUEST,
id,
};
};
}
export function authorizeFollowRequestSuccess(id) {
return {
type: FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
id,
};
};
}
export function authorizeFollowRequestFail(id, error) {
return {
@ -700,7 +700,7 @@ export function authorizeFollowRequestFail(id, error) {
id,
error,
};
};
}
export function rejectFollowRequest(id) {
@ -712,21 +712,21 @@ export function rejectFollowRequest(id) {
.then(() => dispatch(rejectFollowRequestSuccess(id)))
.catch(error => dispatch(rejectFollowRequestFail(id, error)));
};
};
}
export function rejectFollowRequestRequest(id) {
return {
type: FOLLOW_REQUEST_REJECT_REQUEST,
id,
};
};
}
export function rejectFollowRequestSuccess(id) {
return {
type: FOLLOW_REQUEST_REJECT_SUCCESS,
id,
};
};
}
export function rejectFollowRequestFail(id, error) {
return {
@ -734,7 +734,7 @@ export function rejectFollowRequestFail(id, error) {
id,
error,
};
};
}
export function pinAccount(id) {
return (dispatch, getState) => {
@ -746,7 +746,7 @@ export function pinAccount(id) {
dispatch(pinAccountFail(error));
});
};
};
}
export function unpinAccount(id) {
return (dispatch, getState) => {
@ -758,49 +758,49 @@ export function unpinAccount(id) {
dispatch(unpinAccountFail(error));
});
};
};
}
export function pinAccountRequest(id) {
return {
type: ACCOUNT_PIN_REQUEST,
id,
};
};
}
export function pinAccountSuccess(relationship) {
return {
type: ACCOUNT_PIN_SUCCESS,
relationship,
};
};
}
export function pinAccountFail(error) {
return {
type: ACCOUNT_PIN_FAIL,
error,
};
};
}
export function unpinAccountRequest(id) {
return {
type: ACCOUNT_UNPIN_REQUEST,
id,
};
};
}
export function unpinAccountSuccess(relationship) {
return {
type: ACCOUNT_UNPIN_SUCCESS,
relationship,
};
};
}
export function unpinAccountFail(error) {
return {
type: ACCOUNT_UNPIN_FAIL,
error,
};
};
}
export const revealAccount = id => ({
type: ACCOUNT_REVEAL,
@ -811,18 +811,18 @@ export function fetchPinnedAccounts() {
return (dispatch, getState) => {
dispatch(fetchPinnedAccountsRequest());
api(getState).get(`/api/v1/endorsements`, { params: { limit: 0 } }).then(response => {
api(getState).get('/api/v1/endorsements', { params: { limit: 0 } }).then(response => {
dispatch(importFetchedAccounts(response.data));
dispatch(fetchPinnedAccountsSuccess(response.data));
}).catch(err => dispatch(fetchPinnedAccountsFail(err)));
};
};
}
export function fetchPinnedAccountsRequest() {
return {
type: PINNED_ACCOUNTS_FETCH_REQUEST,
};
};
}
export function fetchPinnedAccountsSuccess(accounts, next) {
return {
@ -830,14 +830,14 @@ export function fetchPinnedAccountsSuccess(accounts, next) {
accounts,
next,
};
};
}
export function fetchPinnedAccountsFail(error) {
return {
type: PINNED_ACCOUNTS_FETCH_FAIL,
error,
};
};
}
export function fetchPinnedAccountsSuggestions(q) {
return (dispatch, getState) => {
@ -853,7 +853,7 @@ export function fetchPinnedAccountsSuggestions(q) {
dispatch(fetchPinnedAccountsSuggestionsReady(q, response.data));
});
};
};
}
export function fetchPinnedAccountsSuggestionsReady(query, accounts) {
return {
@ -861,24 +861,24 @@ export function fetchPinnedAccountsSuggestionsReady(query, accounts) {
query,
accounts,
};
};
}
export function clearPinnedAccountsSuggestions() {
return {
type: PINNED_ACCOUNTS_EDITOR_SUGGESTIONS_CLEAR,
};
};
}
export function changePinnedAccountsSuggestions(value) {
return {
type: PINNED_ACCOUNTS_EDITOR_SUGGESTIONS_CHANGE,
value,
}
};
};
}
export function resetPinnedAccountsEditor() {
return {
type: PINNED_ACCOUNTS_EDITOR_RESET,
};
};
}

@ -17,13 +17,13 @@ export function dismissAlert(alert) {
type: ALERT_DISMISS,
alert,
};
};
}
export function clearAlert() {
return {
type: ALERT_CLEAR,
};
};
}
export function showAlert(title = messages.unexpectedTitle, message = messages.unexpectedMessage, message_values = undefined) {
return {
@ -32,7 +32,7 @@ export function showAlert(title = messages.unexpectedTitle, message = messages.u
message,
message_values,
};
};
}
export function showAlertForError(error, skipNotFound = false) {
if (error.response) {

@ -24,13 +24,13 @@ export function fetchBlocks() {
dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => dispatch(fetchBlocksFail(error)));
};
};
}
export function fetchBlocksRequest() {
return {
type: BLOCKS_FETCH_REQUEST,
};
};
}
export function fetchBlocksSuccess(accounts, next) {
return {
@ -38,14 +38,14 @@ export function fetchBlocksSuccess(accounts, next) {
accounts,
next,
};
};
}
export function fetchBlocksFail(error) {
return {
type: BLOCKS_FETCH_FAIL,
error,
};
};
}
export function expandBlocks() {
return (dispatch, getState) => {
@ -64,13 +64,13 @@ export function expandBlocks() {
dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => dispatch(expandBlocksFail(error)));
};
};
}
export function expandBlocksRequest() {
return {
type: BLOCKS_EXPAND_REQUEST,
};
};
}
export function expandBlocksSuccess(accounts, next) {
return {
@ -78,14 +78,14 @@ export function expandBlocksSuccess(accounts, next) {
accounts,
next,
};
};
}
export function expandBlocksFail(error) {
return {
type: BLOCKS_EXPAND_FAIL,
error,
};
};
}
export function initBlockModal(account) {
return dispatch => {

@ -25,13 +25,13 @@ export function fetchBookmarkedStatuses() {
dispatch(fetchBookmarkedStatusesFail(error));
});
};
};
}
export function fetchBookmarkedStatusesRequest() {
return {
type: BOOKMARKED_STATUSES_FETCH_REQUEST,
};
};
}
export function fetchBookmarkedStatusesSuccess(statuses, next) {
return {
@ -39,14 +39,14 @@ export function fetchBookmarkedStatusesSuccess(statuses, next) {
statuses,
next,
};
};
}
export function fetchBookmarkedStatusesFail(error) {
return {
type: BOOKMARKED_STATUSES_FETCH_FAIL,
error,
};
};
}
export function expandBookmarkedStatuses() {
return (dispatch, getState) => {
@ -66,13 +66,13 @@ export function expandBookmarkedStatuses() {
dispatch(expandBookmarkedStatusesFail(error));
});
};
};
}
export function expandBookmarkedStatusesRequest() {
return {
type: BOOKMARKED_STATUSES_EXPAND_REQUEST,
};
};
}
export function expandBookmarkedStatusesSuccess(statuses, next) {
return {
@ -80,11 +80,11 @@ export function expandBookmarkedStatusesSuccess(statuses, next) {
statuses,
next,
};
};
}
export function expandBookmarkedStatusesFail(error) {
return {
type: BOOKMARKED_STATUSES_EXPAND_FAIL,
error,
};
};
}

@ -11,7 +11,7 @@ export function initBoostModal(props) {
dispatch({
type: BOOSTS_INIT_MODAL,
privacy
privacy,
});
dispatch(openModal('BOOST', props));

@ -15,7 +15,7 @@ export function addColumn(id, params) {
dispatch(saveSettings());
};
};
}
export function removeColumn(uuid) {
return dispatch => {
@ -26,7 +26,7 @@ export function removeColumn(uuid) {
dispatch(saveSettings());
};
};
}
export function moveColumn(uuid, direction) {
return dispatch => {
@ -38,7 +38,7 @@ export function moveColumn(uuid, direction) {
dispatch(saveSettings());
};
};
}
export function changeColumnParams(uuid, path, value) {
return dispatch => {

@ -101,20 +101,20 @@ export function setComposeToStatus(status, text, spoiler_text, content_type) {
spoiler_text,
content_type,
};
};
}
export function changeCompose(text) {
return {
type: COMPOSE_CHANGE,
text: text,
};
};
}
export function cycleElefriendCompose() {
return {
type: COMPOSE_CYCLE_ELEFRIEND,
};
};
}
export function replyCompose(status, routerHistory) {
return (dispatch, getState) => {
@ -127,19 +127,19 @@ export function replyCompose(status, routerHistory) {
ensureComposeIsVisible(getState, routerHistory);
};
};
}
export function cancelReplyCompose() {
return {
type: COMPOSE_REPLY_CANCEL,
};
};
}
export function resetCompose() {
return {
type: COMPOSE_RESET,
};
};
}
export function mentionCompose(account, routerHistory) {
return (dispatch, getState) => {
@ -150,7 +150,7 @@ export function mentionCompose(account, routerHistory) {
ensureComposeIsVisible(getState, routerHistory);
};
};
}
export function directCompose(account, routerHistory) {
return (dispatch, getState) => {
@ -161,7 +161,7 @@ export function directCompose(account, routerHistory) {
ensureComposeIsVisible(getState, routerHistory);
};
};
}
export function submitCompose(routerHistory) {
return function (dispatch, getState) {
@ -257,34 +257,34 @@ export function submitCompose(routerHistory) {
dispatch(submitComposeFail(error));
});
};
};
}
export function submitComposeRequest() {
return {
type: COMPOSE_SUBMIT_REQUEST,
};
};
}
export function submitComposeSuccess(status) {
return {
type: COMPOSE_SUBMIT_SUCCESS,
status: status,
};
};
}
export function submitComposeFail(error) {
return {
type: COMPOSE_SUBMIT_FAIL,
error: error,
};
};
}
export function doodleSet(options) {
return {
type: COMPOSE_DOODLE_SET,
options: options,
};
};
}
export function uploadCompose(files) {
return function (dispatch, getState) {
@ -347,9 +347,9 @@ export function uploadCompose(files) {
}
});
}).catch(error => dispatch(uploadComposeFail(error)));
};
}
};
};
}
export const uploadComposeProcessing = () => ({
type: COMPOSE_UPLOAD_PROCESSING,
@ -407,14 +407,14 @@ export function initMediaEditModal(id) {
dispatch(openModal('FOCAL_POINT', { id }));
};
};
}
export function onChangeMediaDescription(description) {
return {
type: COMPOSE_CHANGE_MEDIA_DESCRIPTION,
description,
};
};
}
export function onChangeMediaFocus(focusX, focusY) {
return {
@ -422,7 +422,7 @@ export function onChangeMediaFocus(focusX, focusY) {
focusX,
focusY,
};
};
}
export function changeUploadCompose(id, params) {
return (dispatch, getState) => {
@ -454,14 +454,14 @@ export function changeUploadCompose(id, params) {
});
}
};
};
}
export function changeUploadComposeRequest() {
return {
type: COMPOSE_UPLOAD_CHANGE_REQUEST,
skipLoading: true,
};
};
}
export function changeUploadComposeSuccess(media, attached) {
return {
@ -470,7 +470,7 @@ export function changeUploadComposeSuccess(media, attached) {
attached: attached,
skipLoading: true,
};
};
}
export function changeUploadComposeFail(error) {
return {
@ -478,14 +478,14 @@ export function changeUploadComposeFail(error) {
error: error,
skipLoading: true,
};
};
}
export function uploadComposeRequest() {
return {
type: COMPOSE_UPLOAD_REQUEST,
skipLoading: true,
};
};
}
export function uploadComposeProgress(loaded, total) {
return {
@ -493,7 +493,7 @@ export function uploadComposeProgress(loaded, total) {
loaded: loaded,
total: total,
};
};
}
export function uploadComposeSuccess(media, file) {
return {
@ -502,7 +502,7 @@ export function uploadComposeSuccess(media, file) {
file: file,
skipLoading: true,
};
};
}
export function uploadComposeFail(error) {
return {
@ -510,14 +510,14 @@ export function uploadComposeFail(error) {
error: error,
skipLoading: true,
};
};
}
export function undoUploadCompose(media_id) {
return {
type: COMPOSE_UPLOAD_UNDO,
media_id: media_id,
};
};
}
export function clearComposeSuggestions() {
if (fetchComposeSuggestionsAccountsController) {
@ -526,7 +526,7 @@ export function clearComposeSuggestions() {
return {
type: COMPOSE_SUGGESTIONS_CLEAR,
};
};
}
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
if (fetchComposeSuggestionsAccountsController) {
@ -603,7 +603,7 @@ export function fetchComposeSuggestions(token) {
break;
}
};
};
}
export function readyComposeSuggestionsEmojis(token, emojis) {
return {
@ -611,7 +611,7 @@ export function readyComposeSuggestionsEmojis(token, emojis) {
token,
emojis,
};
};
}
export function readyComposeSuggestionsAccounts(token, accounts) {
return {
@ -619,7 +619,7 @@ export function readyComposeSuggestionsAccounts(token, accounts) {
token,
accounts,
};
};
}
export const readyComposeSuggestionsTags = (token, tags) => ({
type: COMPOSE_SUGGESTIONS_READY,
@ -659,7 +659,7 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
});
}
};
};
}
export function updateSuggestionTags(token) {
return {
@ -707,13 +707,13 @@ export function mountCompose() {
return {
type: COMPOSE_MOUNT,
};
};
}
export function unmountCompose() {
return {
type: COMPOSE_UNMOUNT,
};
};
}
export function changeComposeAdvancedOption(option, value) {
return {
@ -727,7 +727,7 @@ export function changeComposeSensitivity() {
return {
type: COMPOSE_SENSITIVITY_CHANGE,
};
};
}
export const changeComposeLanguage = language => ({
type: COMPOSE_LANGUAGE_CHANGE,
@ -738,28 +738,28 @@ export function changeComposeSpoilerness() {
return {
type: COMPOSE_SPOILERNESS_CHANGE,
};
};
}
export function changeComposeSpoilerText(text) {
return {
type: COMPOSE_SPOILER_TEXT_CHANGE,
text,
};
};
}
export function changeComposeVisibility(value) {
return {
type: COMPOSE_VISIBILITY_CHANGE,
value,
};
};
}
export function changeComposeContentType(value) {
return {
type: COMPOSE_CONTENT_TYPE_CHANGE,
value,
};
};
}
export function insertEmojiCompose(position, emoji) {
return {
@ -767,26 +767,26 @@ export function insertEmojiCompose(position, emoji) {
position,
emoji,
};
};
}
export function addPoll() {
return {
type: COMPOSE_POLL_ADD,
};
};
}
export function removePoll() {
return {
type: COMPOSE_POLL_REMOVE,
};
};
}
export function addPollOption(title) {
return {
type: COMPOSE_POLL_OPTION_ADD,
title,
};
};
}
export function changePollOption(index, title) {
return {
@ -794,14 +794,14 @@ export function changePollOption(index, title) {
index,
title,
};
};
}
export function removePollOption(index) {
return {
type: COMPOSE_POLL_OPTION_REMOVE,
index,
};
};
}
export function changePollSettings(expiresIn, isMultiple) {
return {
@ -809,4 +809,4 @@ export function changePollSettings(expiresIn, isMultiple) {
expiresIn,
isMultiple,
};
};
}

@ -14,14 +14,14 @@ export function fetchCustomEmojis() {
dispatch(fetchCustomEmojisFail(error));
});
};
};
}
export function fetchCustomEmojisRequest() {
return {
type: CUSTOM_EMOJIS_FETCH_REQUEST,
skipLoading: true,
};
};
}
export function fetchCustomEmojisSuccess(custom_emojis) {
return {
@ -29,7 +29,7 @@ export function fetchCustomEmojisSuccess(custom_emojis) {
custom_emojis,
skipLoading: true,
};
};
}
export function fetchCustomEmojisFail(error) {
return {
@ -37,4 +37,4 @@ export function fetchCustomEmojisFail(error) {
error,
skipLoading: true,
};
};
}

@ -29,14 +29,14 @@ export function blockDomain(domain) {
dispatch(blockDomainFail(domain, err));
});
};
};
}
export function blockDomainRequest(domain) {
return {
type: DOMAIN_BLOCK_REQUEST,
domain,
};
};
}
export function blockDomainSuccess(domain, accounts) {
return {
@ -44,7 +44,7 @@ export function blockDomainSuccess(domain, accounts) {
domain,
accounts,
};
};
}
export function blockDomainFail(domain, error) {
return {
@ -52,7 +52,7 @@ export function blockDomainFail(domain, error) {
domain,
error,
};
};
}
export function unblockDomain(domain) {
return (dispatch, getState) => {
@ -66,14 +66,14 @@ export function unblockDomain(domain) {
dispatch(unblockDomainFail(domain, err));
});
};
};
}
export function unblockDomainRequest(domain) {
return {
type: DOMAIN_UNBLOCK_REQUEST,
domain,
};
};
}
export function unblockDomainSuccess(domain, accounts) {
return {
@ -81,7 +81,7 @@ export function unblockDomainSuccess(domain, accounts) {
domain,
accounts,
};
};
}
export function unblockDomainFail(domain, error) {
return {
@ -89,7 +89,7 @@ export function unblockDomainFail(domain, error) {
domain,
error,
};
};
}
export function fetchDomainBlocks() {
return (dispatch, getState) => {
@ -102,13 +102,13 @@ export function fetchDomainBlocks() {
dispatch(fetchDomainBlocksFail(err));
});
};
};
}
export function fetchDomainBlocksRequest() {
return {
type: DOMAIN_BLOCKS_FETCH_REQUEST,
};
};
}
export function fetchDomainBlocksSuccess(domains, next) {
return {
@ -116,14 +116,14 @@ export function fetchDomainBlocksSuccess(domains, next) {
domains,
next,
};
};
}
export function fetchDomainBlocksFail(error) {
return {
type: DOMAIN_BLOCKS_FETCH_FAIL,
error,
};
};
}
export function expandDomainBlocks() {
return (dispatch, getState) => {
@ -142,13 +142,13 @@ export function expandDomainBlocks() {
dispatch(expandDomainBlocksFail(err));
});
};
};
}
export function expandDomainBlocksRequest() {
return {
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
};
};
}
export function expandDomainBlocksSuccess(domains, next) {
return {
@ -156,11 +156,11 @@ export function expandDomainBlocksSuccess(domains, next) {
domains,
next,
};
};
}
export function expandDomainBlocksFail(error) {
return {
type: DOMAIN_BLOCKS_EXPAND_FAIL,
error,
};
};
}

@ -11,4 +11,4 @@ export function useEmoji(emoji) {
dispatch(saveSettings());
};
};
}

@ -25,14 +25,14 @@ export function fetchFavouritedStatuses() {
dispatch(fetchFavouritedStatusesFail(error));
});
};
};
}
export function fetchFavouritedStatusesRequest() {
return {
type: FAVOURITED_STATUSES_FETCH_REQUEST,
skipLoading: true,
};
};
}
export function fetchFavouritedStatusesSuccess(statuses, next) {
return {
@ -41,7 +41,7 @@ export function fetchFavouritedStatusesSuccess(statuses, next) {
next,
skipLoading: true,
};
};
}
export function fetchFavouritedStatusesFail(error) {
return {
@ -49,7 +49,7 @@ export function fetchFavouritedStatusesFail(error) {
error,
skipLoading: true,
};
};
}
export function expandFavouritedStatuses() {
return (dispatch, getState) => {
@ -69,13 +69,13 @@ export function expandFavouritedStatuses() {
dispatch(expandFavouritedStatusesFail(error));
});
};
};
}
export function expandFavouritedStatusesRequest() {
return {
type: FAVOURITED_STATUSES_EXPAND_REQUEST,
};
};
}
export function expandFavouritedStatusesSuccess(statuses, next) {
return {
@ -83,11 +83,11 @@ export function expandFavouritedStatusesSuccess(statuses, next) {
statuses,
next,
};
};
}
export function expandFavouritedStatusesFail(error) {
return {
type: FAVOURITED_STATUSES_EXPAND_FAIL,
error,
};
};
}

@ -8,10 +8,10 @@ export function setHeight (key, id, height) {
id,
height,
};
};
}
export function clearHeight () {
return {
type: HEIGHT_CACHE_CLEAR,
};
};
}

@ -54,7 +54,7 @@ export function reblog(status, visibility) {
dispatch(reblogFail(status, error));
});
};
};
}
export function unreblog(status) {
return (dispatch, getState) => {
@ -67,21 +67,21 @@ export function unreblog(status) {
dispatch(unreblogFail(status, error));
});
};
};
}
export function reblogRequest(status) {
return {
type: REBLOG_REQUEST,
status: status,
};
};
}
export function reblogSuccess(status) {
return {
type: REBLOG_SUCCESS,
status: status,
};
};
}
export function reblogFail(status, error) {
return {
@ -89,21 +89,21 @@ export function reblogFail(status, error) {
status: status,
error: error,
};
};
}
export function unreblogRequest(status) {
return {
type: UNREBLOG_REQUEST,
status: status,
};
};
}
export function unreblogSuccess(status) {
return {
type: UNREBLOG_SUCCESS,
status: status,
};
};
}
export function unreblogFail(status, error) {
return {
@ -111,7 +111,7 @@ export function unreblogFail(status, error) {
status: status,
error: error,
};
};
}
export function favourite(status) {
return function (dispatch, getState) {
@ -124,7 +124,7 @@ export function favourite(status) {
dispatch(favouriteFail(status, error));
});
};
};
}
export function unfavourite(status) {
return (dispatch, getState) => {
@ -137,21 +137,21 @@ export function unfavourite(status) {
dispatch(unfavouriteFail(status, error));
});
};
};
}
export function favouriteRequest(status) {
return {
type: FAVOURITE_REQUEST,
status: status,
};
};
}
export function favouriteSuccess(status) {
return {
type: FAVOURITE_SUCCESS,
status: status,
};
};
}
export function favouriteFail(status, error) {
return {
@ -159,21 +159,21 @@ export function favouriteFail(status, error) {
status: status,
error: error,
};
};
}
export function unfavouriteRequest(status) {
return {
type: UNFAVOURITE_REQUEST,
status: status,
};
};
}
export function unfavouriteSuccess(status) {
return {
type: UNFAVOURITE_SUCCESS,
status: status,
};
};
}
export function unfavouriteFail(status, error) {
return {
@ -181,7 +181,7 @@ export function unfavouriteFail(status, error) {
status: status,
error: error,
};
};
}
export function bookmark(status) {
return function (dispatch, getState) {
@ -194,7 +194,7 @@ export function bookmark(status) {
dispatch(bookmarkFail(status, error));
});
};
};
}
export function unbookmark(status) {
return (dispatch, getState) => {
@ -207,21 +207,21 @@ export function unbookmark(status) {
dispatch(unbookmarkFail(status, error));
});
};
};
}
export function bookmarkRequest(status) {
return {
type: BOOKMARK_REQUEST,
status: status,
};
};
}
export function bookmarkSuccess(status) {
return {
type: BOOKMARK_SUCCESS,
status: status,
};
};
}
export function bookmarkFail(status, error) {
return {
@ -229,21 +229,21 @@ export function bookmarkFail(status, error) {
status: status,
error: error,
};
};
}
export function unbookmarkRequest(status) {
return {
type: UNBOOKMARK_REQUEST,
status: status,
};
};
}
export function unbookmarkSuccess(status) {
return {
type: UNBOOKMARK_SUCCESS,
status: status,
};
};
}
export function unbookmarkFail(status, error) {
return {
@ -251,7 +251,7 @@ export function unbookmarkFail(status, error) {
status: status,
error: error,
};
};
}
export function fetchReblogs(id) {
return (dispatch, getState) => {
@ -264,14 +264,14 @@ export function fetchReblogs(id) {
dispatch(fetchReblogsFail(id, error));
});
};
};
}
export function fetchReblogsRequest(id) {
return {
type: REBLOGS_FETCH_REQUEST,
id,
};
};
}
export function fetchReblogsSuccess(id, accounts) {
return {
@ -279,14 +279,14 @@ export function fetchReblogsSuccess(id, accounts) {
id,
accounts,
};
};
}
export function fetchReblogsFail(id, error) {
return {
type: REBLOGS_FETCH_FAIL,
error,
};
};
}
export function fetchFavourites(id) {
return (dispatch, getState) => {
@ -299,14 +299,14 @@ export function fetchFavourites(id) {
dispatch(fetchFavouritesFail(id, error));
});
};
};
}
export function fetchFavouritesRequest(id) {
return {
type: FAVOURITES_FETCH_REQUEST,
id,
};
};
}
export function fetchFavouritesSuccess(id, accounts) {
return {
@ -314,14 +314,14 @@ export function fetchFavouritesSuccess(id, accounts) {
id,
accounts,
};
};
}
export function fetchFavouritesFail(id, error) {
return {
type: FAVOURITES_FETCH_FAIL,
error,
};
};
}
export function pin(status) {
return (dispatch, getState) => {
@ -334,21 +334,21 @@ export function pin(status) {
dispatch(pinFail(status, error));
});
};
};
}
export function pinRequest(status) {
return {
type: PIN_REQUEST,
status,
};
};
}
export function pinSuccess(status) {
return {
type: PIN_SUCCESS,
status,
};
};
}
export function pinFail(status, error) {
return {
@ -356,7 +356,7 @@ export function pinFail(status, error) {
status,
error,
};
};
}
export function unpin (status) {
return (dispatch, getState) => {
@ -369,21 +369,21 @@ export function unpin (status) {
dispatch(unpinFail(status, error));
});
};
};
}
export function unpinRequest(status) {
return {
type: UNPIN_REQUEST,
status,
};
};
}
export function unpinSuccess(status) {
return {
type: UNPIN_SUCCESS,
status,
};
};
}
export function unpinFail(status, error) {
return {
@ -391,4 +391,4 @@ export function unpinFail(status, error) {
status,
error,
};
};
}

@ -33,14 +33,14 @@ export function checkDeprecatedLocalSettings() {
}));
}
};
};
}
export function clearDeprecatedLocalSettings() {
return (dispatch) => {
dispatch(deleteLocalSetting(['content_warnings', 'auto_unfold']));
dispatch(deleteLocalSetting(['swipe_to_change_columns']));
};
};
}
export function changeLocalSetting(key, value) {
return dispatch => {
@ -52,7 +52,7 @@ export function changeLocalSetting(key, value) {
dispatch(saveLocalSettings());
};
};
}
export function deleteLocalSetting(key) {
return dispatch => {
@ -63,7 +63,7 @@ export function deleteLocalSetting(key) {
dispatch(saveLocalSettings());
};
};
}
// __TODO :__
// Right now `saveLocalSettings()` doesn't keep track of which user
@ -74,4 +74,4 @@ export function saveLocalSettings() {
const localSettings = getState().get('local_settings').toJS();
localStorage.setItem('mastodon-settings', JSON.stringify(localSettings));
};
};
}

@ -101,7 +101,7 @@ export function submitMarkersSuccess({ home, notifications }) {
home: (home || {}).last_read_id,
notifications: (notifications || {}).last_read_id,
};
};
}
export function submitMarkers(params = {}) {
const result = (dispatch, getState) => debouncedSubmitMarkers(dispatch, getState);
@ -111,7 +111,7 @@ export function submitMarkers(params = {}) {
}
return result;
};
}
export const fetchMarkers = () => (dispatch, getState) => {
const params = { timeline: ['notifications'] };
@ -130,7 +130,7 @@ export function fetchMarkersRequest() {
type: MARKERS_FETCH_REQUEST,
skipLoading: true,
};
};
}
export function fetchMarkersSuccess(markers) {
return {
@ -138,7 +138,7 @@ export function fetchMarkersSuccess(markers) {
markers,
skipLoading: true,
};
};
}
export function fetchMarkersFail(error) {
return {
@ -147,4 +147,4 @@ export function fetchMarkersFail(error) {
skipLoading: true,
skipAlert: true,
};
};
}

@ -7,7 +7,7 @@ export function openModal(type, props) {
modalType: type,
modalProps: props,
};
};
}
export function closeModal(type, options = { ignoreFocus: false }) {
return {
@ -15,4 +15,4 @@ export function closeModal(type, options = { ignoreFocus: false }) {
modalType: type,
ignoreFocus: options.ignoreFocus,
};
};
}

@ -26,13 +26,13 @@ export function fetchMutes() {
dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => dispatch(fetchMutesFail(error)));
};
};
}
export function fetchMutesRequest() {
return {
type: MUTES_FETCH_REQUEST,
};
};
}
export function fetchMutesSuccess(accounts, next) {
return {
@ -40,14 +40,14 @@ export function fetchMutesSuccess(accounts, next) {
accounts,
next,
};
};
}
export function fetchMutesFail(error) {
return {
type: MUTES_FETCH_FAIL,
error,
};
};
}
export function expandMutes() {
return (dispatch, getState) => {
@ -66,13 +66,13 @@ export function expandMutes() {
dispatch(fetchRelationships(response.data.map(item => item.id)));
}).catch(error => dispatch(expandMutesFail(error)));
};
};
}
export function expandMutesRequest() {
return {
type: MUTES_EXPAND_REQUEST,
};
};
}
export function expandMutesSuccess(accounts, next) {
return {
@ -80,14 +80,14 @@ export function expandMutesSuccess(accounts, next) {
accounts,
next,
};
};
}
export function expandMutesFail(error) {
return {
type: MUTES_EXPAND_FAIL,
error,
};
};
}
export function initMuteModal(account) {
return dispatch => {

@ -129,7 +129,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
});
}
};
};
}
const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
@ -209,14 +209,14 @@ export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
done();
});
};
};
}
export function expandNotificationsRequest(isLoadingMore) {
return {
type: NOTIFICATIONS_EXPAND_REQUEST,
skipLoading: !isLoadingMore,
};
};
}
export function expandNotificationsSuccess(notifications, next, isLoadingMore, isLoadingRecent, usePendingItems) {
return {
@ -227,7 +227,7 @@ export function expandNotificationsSuccess(notifications, next, isLoadingMore, i
usePendingItems,
skipLoading: !isLoadingMore,
};
};
}
export function expandNotificationsFail(error, isLoadingMore) {
return {
@ -236,7 +236,7 @@ export function expandNotificationsFail(error, isLoadingMore) {
skipLoading: !isLoadingMore,
skipAlert: !isLoadingMore || error.name === 'AbortError',
};
};
}
export function clearNotifications() {
return (dispatch, getState) => {
@ -246,14 +246,14 @@ export function clearNotifications() {
api(getState).post('/api/v1/notifications/clear');
};
};
}
export function scrollTopNotifications(top) {
return {
type: NOTIFICATIONS_SCROLL_TOP,
top,
};
};
}
export function deleteMarkedNotifications() {
return (dispatch, getState) => {
@ -277,33 +277,33 @@ export function deleteMarkedNotifications() {
dispatch(deleteMarkedNotificationsFail(error));
});
};
};
}
export function enterNotificationClearingMode(yes) {
return {
type: NOTIFICATIONS_ENTER_CLEARING_MODE,
yes: yes,
};
};
}
export function markAllNotifications(yes) {
return {
type: NOTIFICATIONS_MARK_ALL_FOR_DELETE,
yes: yes, // true, false or null. null = invert
};
};
}
export function deleteMarkedNotificationsRequest() {
return {
type: NOTIFICATIONS_DELETE_MARKED_REQUEST,
};
};
}
export function deleteMarkedNotificationsFail() {
return {
type: NOTIFICATIONS_DELETE_MARKED_FAIL,
};
};
}
export function markNotificationForDelete(id, yes) {
return {
@ -311,32 +311,32 @@ export function markNotificationForDelete(id, yes) {
id: id,
yes: yes,
};
};
}
export function deleteMarkedNotificationsSuccess() {
return {
type: NOTIFICATIONS_DELETE_MARKED_SUCCESS,
};
};
}
export function mountNotifications() {
return {
type: NOTIFICATIONS_MOUNT,
};
};
}
export function unmountNotifications() {
return {
type: NOTIFICATIONS_UNMOUNT,
};
};
}
export function notificationsSetVisibility(visibility) {
return {
type: NOTIFICATIONS_SET_VISIBILITY,
visibility: visibility,
};
};
}
export function setFilter (filterType) {
return dispatch => {
@ -348,13 +348,13 @@ export function setFilter (filterType) {
dispatch(expandNotifications({ forceLoad: true }));
dispatch(saveSettings());
};
};
}
export function markNotificationsAsRead() {
return {
type: NOTIFICATIONS_MARK_AS_READ,
};
};
}
// Browser support
export function setupBrowserNotifications() {
@ -379,7 +379,7 @@ export function requestBrowserPermission(callback = noOp) {
callback(permission);
});
};
};
}
export function setBrowserSupport (value) {
return {

@ -11,4 +11,4 @@ export function showOnboardingOnce() {
dispatch(saveSettings());
}
};
};
}

@ -18,13 +18,13 @@ export function fetchPinnedStatuses() {
dispatch(fetchPinnedStatusesFail(error));
});
};
};
}
export function fetchPinnedStatusesRequest() {
return {
type: PINNED_STATUSES_FETCH_REQUEST,
};
};
}
export function fetchPinnedStatusesSuccess(statuses, next) {
return {
@ -32,11 +32,11 @@ export function fetchPinnedStatusesSuccess(statuses, next) {
statuses,
next,
};
};
}
export function fetchPinnedStatusesFail(error) {
return {
type: PINNED_STATUSES_FETCH_FAIL,
error,
};
};
}

@ -19,13 +19,13 @@ export function changeSearch(value) {
type: SEARCH_CHANGE,
value,
};
};
}
export function clearSearch() {
return {
type: SEARCH_CLEAR,
};
};
}
export function submitSearch() {
return (dispatch, getState) => {
@ -60,13 +60,13 @@ export function submitSearch() {
dispatch(fetchSearchFail(error));
});
};
};
}
export function fetchSearchRequest() {
return {
type: SEARCH_FETCH_REQUEST,
};
};
}
export function fetchSearchSuccess(results, searchTerm) {
return {
@ -74,14 +74,14 @@ export function fetchSearchSuccess(results, searchTerm) {
results,
searchTerm,
};
};
}
export function fetchSearchFail(error) {
return {
type: SEARCH_FETCH_FAIL,
error,
};
};
}
export const expandSearch = type => (dispatch, getState) => {
const value = getState().getIn(['search', 'value']);

@ -15,7 +15,7 @@ export function changeSetting(path, value) {
dispatch(saveSettings());
};
};
}
const debouncedSave = debounce((dispatch, getState) => {
if (getState().getIn(['settings', 'saved'])) {
@ -31,4 +31,4 @@ const debouncedSave = debounce((dispatch, getState) => {
export function saveSettings() {
return (dispatch, getState) => debouncedSave(dispatch, getState);
};
}

@ -45,7 +45,7 @@ export function fetchStatusRequest(id, skipLoading) {
id,
skipLoading,
};
};
}
export function fetchStatus(id, forceFetch = false) {
return (dispatch, getState) => {
@ -66,14 +66,14 @@ export function fetchStatus(id, forceFetch = false) {
dispatch(fetchStatusFail(id, error, skipLoading));
});
};
};
}
export function fetchStatusSuccess(skipLoading) {
return {
type: STATUS_FETCH_SUCCESS,
skipLoading,
};
};
}
export function fetchStatusFail(id, error, skipLoading) {
return {
@ -83,7 +83,7 @@ export function fetchStatusFail(id, error, skipLoading) {
skipLoading,
skipAlert: true,
};
};
}
export function redraft(status, raw_text, content_type) {
return {
@ -92,7 +92,7 @@ export function redraft(status, raw_text, content_type) {
raw_text,
content_type,
};
};
}
export const editStatus = (id, routerHistory) => (dispatch, getState) => {
let status = getState().getIn(['statuses', id]);
@ -148,21 +148,21 @@ export function deleteStatus(id, routerHistory, withRedraft = false) {
dispatch(deleteStatusFail(id, error));
});
};
};
}
export function deleteStatusRequest(id) {
return {
type: STATUS_DELETE_REQUEST,
id: id,
};
};
}
export function deleteStatusSuccess(id) {
return {
type: STATUS_DELETE_SUCCESS,
id: id,
};
};
}
export function deleteStatusFail(id, error) {
return {
@ -170,7 +170,7 @@ export function deleteStatusFail(id, error) {
id: id,
error: error,
};
};
}
export const updateStatus = status => dispatch =>
dispatch(importFetchedStatus(status));
@ -191,14 +191,14 @@ export function fetchContext(id) {
dispatch(fetchContextFail(id, error));
});
};
};
}
export function fetchContextRequest(id) {
return {
type: CONTEXT_FETCH_REQUEST,
id,
};
};
}
export function fetchContextSuccess(id, ancestors, descendants) {
return {
@ -208,7 +208,7 @@ export function fetchContextSuccess(id, ancestors, descendants) {
descendants,
statuses: ancestors.concat(descendants),
};
};
}
export function fetchContextFail(id, error) {
return {
@ -217,7 +217,7 @@ export function fetchContextFail(id, error) {
error,
skipAlert: true,
};
};
}
export function muteStatus(id) {
return (dispatch, getState) => {
@ -229,21 +229,21 @@ export function muteStatus(id) {
dispatch(muteStatusFail(id, error));
});
};
};
}
export function muteStatusRequest(id) {
return {
type: STATUS_MUTE_REQUEST,
id,
};
};
}
export function muteStatusSuccess(id) {
return {
type: STATUS_MUTE_SUCCESS,
id,
};
};
}
export function muteStatusFail(id, error) {
return {
@ -251,7 +251,7 @@ export function muteStatusFail(id, error) {
id,
error,
};
};
}
export function unmuteStatus(id) {
return (dispatch, getState) => {
@ -263,21 +263,21 @@ export function unmuteStatus(id) {
dispatch(unmuteStatusFail(id, error));
});
};
};
}
export function unmuteStatusRequest(id) {
return {
type: STATUS_UNMUTE_REQUEST,
id,
};
};
}
export function unmuteStatusSuccess(id) {
return {
type: STATUS_UNMUTE_SUCCESS,
id,
};
};
}
export function unmuteStatusFail(id, error) {
return {
@ -285,7 +285,7 @@ export function unmuteStatusFail(id, error) {
id,
error,
};
};
}
export function hideStatus(ids) {
if (!Array.isArray(ids)) {
@ -296,7 +296,7 @@ export function hideStatus(ids) {
type: STATUS_HIDE,
ids,
};
};
}
export function revealStatus(ids) {
if (!Array.isArray(ids)) {
@ -307,7 +307,7 @@ export function revealStatus(ids) {
type: STATUS_REVEAL,
ids,
};
};
}
export function toggleStatusCollapse(id, isCollapsed) {
return {
@ -315,7 +315,7 @@ export function toggleStatusCollapse(id, isCollapsed) {
id,
isCollapsed,
};
};
}
export const translateStatus = id => (dispatch, getState) => {
dispatch(translateStatusRequest(id));

@ -18,7 +18,7 @@ const applyMigrations = (state) => {
if (state.getIn(['settings', 'notifications', 'showUnread']) !== false) {
state.setIn(['settings', 'notifications', 'showUnread'], state.getIn(['local_settings', 'notifications', 'show_unread']));
}
state.removeIn(['local_settings', 'notifications', 'show_unread'])
state.removeIn(['local_settings', 'notifications', 'show_unread']);
}
});
};
@ -36,4 +36,4 @@ export function hydrateStore(rawState) {
dispatch(importFetchedAccounts(Object.values(rawState.accounts)));
dispatch(saveSettings());
};
};
}

@ -21,14 +21,14 @@ export function fetchSuggestions(withRelationships = false) {
}
}).catch(error => dispatch(fetchSuggestionsFail(error)));
};
};
}
export function fetchSuggestionsRequest() {
return {
type: SUGGESTIONS_FETCH_REQUEST,
skipLoading: true,
};
};
}
export function fetchSuggestionsSuccess(suggestions) {
return {
@ -36,7 +36,7 @@ export function fetchSuggestionsSuccess(suggestions) {
suggestions,
skipLoading: true,
};
};
}
export function fetchSuggestionsFail(error) {
return {
@ -45,7 +45,7 @@ export function fetchSuggestionsFail(error) {
skipLoading: true,
skipAlert: true,
};
};
}
export const dismissSuggestion = accountId => (dispatch, getState) => {
dispatch({

@ -60,7 +60,7 @@ export function fetchFollowedHashtagsRequest() {
return {
type: FOLLOWED_HASHTAGS_FETCH_REQUEST,
};
};
}
export function fetchFollowedHashtagsSuccess(followed_tags, next) {
return {
@ -68,14 +68,14 @@ export function fetchFollowedHashtagsSuccess(followed_tags, next) {
followed_tags,
next,
};
};
}
export function fetchFollowedHashtagsFail(error) {
return {
type: FOLLOWED_HASHTAGS_FETCH_FAIL,
error,
};
};
}
export function expandFollowedHashtags() {
return (dispatch, getState) => {
@ -94,13 +94,13 @@ export function expandFollowedHashtags() {
dispatch(expandFollowedHashtagsFail(error));
});
};
};
}
export function expandFollowedHashtagsRequest() {
return {
type: FOLLOWED_HASHTAGS_EXPAND_REQUEST,
};
};
}
export function expandFollowedHashtagsSuccess(followed_tags, next) {
return {
@ -108,14 +108,14 @@ export function expandFollowedHashtagsSuccess(followed_tags, next) {
followed_tags,
next,
};
};
}
export function expandFollowedHashtagsFail(error) {
return {
type: FOLLOWED_HASHTAGS_EXPAND_FAIL,
error,
};
};
}
export const followHashtag = name => (dispatch, getState) => {
dispatch(followHashtagRequest(name));

@ -55,14 +55,14 @@ export function updateTimeline(timeline, status, accept) {
timeline,
status,
usePendingItems: preferPendingItems,
filtered
filtered,
});
if (timeline === 'home') {
dispatch(submitMarkers());
}
};
};
}
export function deleteFromTimelines(id) {
return (dispatch, getState) => {
@ -78,13 +78,13 @@ export function deleteFromTimelines(id) {
reblogOf,
});
};
};
}
export function clearTimeline(timeline) {
return (dispatch) => {
dispatch({ type: TIMELINE_CLEAR, timeline });
};
};
}
const noOp = () => {};
@ -134,7 +134,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
done();
});
};
};
}
export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
return (dispatch, getState) => {
@ -181,7 +181,7 @@ export function expandTimelineRequest(timeline, isLoadingMore) {
timeline,
skipLoading: !isLoadingMore,
};
};
}
export function expandTimelineSuccess(timeline, statuses, next, partial, isLoadingRecent, isLoadingMore, usePendingItems) {
return {
@ -194,7 +194,7 @@ export function expandTimelineSuccess(timeline, statuses, next, partial, isLoadi
usePendingItems,
skipLoading: !isLoadingMore,
};
};
}
export function expandTimelineFail(timeline, error, isLoadingMore) {
return {
@ -204,7 +204,7 @@ export function expandTimelineFail(timeline, error, isLoadingMore) {
skipLoading: !isLoadingMore,
skipNotFound: timeline.startsWith('account:'),
};
};
}
export function scrollTopTimeline(timeline, top) {
return {
@ -212,7 +212,7 @@ export function scrollTopTimeline(timeline, top) {
timeline,
top,
};
};
}
export function connectTimeline(timeline) {
return {
@ -220,7 +220,7 @@ export function connectTimeline(timeline) {
timeline,
usePendingItems: preferPendingItems,
};
};
}
export const disconnectTimeline = timeline => ({
type: TIMELINE_DISCONNECT,

@ -8,4 +8,4 @@ export default function compareId (id1, id2) {
} else {
return id1.length > id2.length ? 1 : -1;
}
};
}

@ -48,27 +48,27 @@ class Account extends ImmutablePureComponent {
handleFollow = () => {
this.props.onFollow(this.props.account);
}
};
handleBlock = () => {
this.props.onBlock(this.props.account);
}
};
handleMute = () => {
this.props.onMute(this.props.account);
}
};
handleMuteNotifications = () => {
this.props.onMuteNotifications(this.props.account, true);
}
};
handleUnmuteNotifications = () => {
this.props.onMuteNotifications(this.props.account, false);
}
};
handleAction = () => {
this.props.onActionClick(this.props.account);
}
};
render () {
const {

@ -137,7 +137,7 @@ export default class Retention extends React.PureComponent {
break;
default:
title = <FormattedMessage id='admin.dashboard.monthly_retention' defaultMessage='User retention rate by month after sign-up' />;
};
}
return (
<div className='retention'>

@ -38,13 +38,13 @@ export default class AnimatedNumber extends React.PureComponent {
const { direction } = this.state;
return { y: -1 * direction };
}
};
willLeave = () => {
const { direction } = this.state;
return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) };
}
};
render () {
const { value, obfuscate } = this.props;

@ -51,6 +51,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
searchTokens: PropTypes.arrayOf(PropTypes.string),
maxLength: PropTypes.number,
lang: PropTypes.string,
spellCheck: PropTypes.string,
};
static defaultProps = {
@ -78,7 +79,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
}
this.props.onChange(e);
}
};
onKeyDown = (e) => {
const { suggestions, disabled } = this.props;
@ -136,22 +137,22 @@ export default class AutosuggestInput extends ImmutablePureComponent {
}
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) {
@ -161,7 +162,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
setInput = (c) => {
this.input = c;
}
};
renderSuggestion = (suggestion, i) => {
const { selectedSuggestion } = this.state;
@ -183,10 +184,10 @@ export default class AutosuggestInput extends ImmutablePureComponent {
{inner}
</div>
);
}
};
render () {
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength, lang } = this.props;
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength, lang, spellCheck } = this.props;
const { suggestionsHidden } = this.state;
return (
@ -212,6 +213,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
className={className}
maxLength={maxLength}
lang={lang}
spellCheck={spellCheck}
/>
</label>

@ -75,7 +75,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
}
this.props.onChange(e);
}
};
onKeyDown = (e) => {
const { suggestions, disabled } = this.props;
@ -133,25 +133,25 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
}
this.props.onKeyDown(e);
}
};
onBlur = () => {
this.setState({ suggestionsHidden: true, focused: false });
}
};
onFocus = (e) => {
this.setState({ focused: true });
if (this.props.onFocus) {
this.props.onFocus(e);
}
}
};
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.textarea.focus();
}
};
componentWillReceiveProps (nextProps) {
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
@ -161,14 +161,14 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
setTextarea = (c) => {
this.textarea = c;
}
};
onPaste = (e) => {
if (e.clipboardData && e.clipboardData.files.length === 1) {
this.props.onPaste(e.clipboardData.files);
e.preventDefault();
}
}
};
renderSuggestion = (suggestion, i) => {
const { selectedSuggestion } = this.state;
@ -190,7 +190,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
{inner}
</div>
);
}
};
render () {
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, lang, children } = this.props;

@ -28,12 +28,12 @@ export default class Avatar extends React.PureComponent {
handleMouseEnter = () => {
if (this.props.animate) return;
this.setState({ hovering: true });
}
};
handleMouseLeave = () => {
if (this.props.animate) return;
this.setState({ hovering: false });
}
};
render () {
const {

@ -19,11 +19,11 @@ export default class Button extends React.PureComponent {
if (!this.props.disabled) {
this.props.onClick(e);
}
}
};
setRef = (c) => {
this.node = c;
}
};
focus() {
this.node.focus();

@ -29,11 +29,11 @@ export default class Column extends React.PureComponent {
}
this._interruptScrollAnimation();
}
};
setRef = c => {
this.node = c;
}
};
componentDidMount () {
if (this.props.bindToDocument) {

@ -26,7 +26,7 @@ export default class ColumnBackButton extends React.PureComponent {
} else {
this.context.router.history.push('/');
}
}
};
render () {
const { multiColumn } = this.props;

@ -21,7 +21,7 @@ export default class ColumnBackButtonSlim extends React.PureComponent {
} else {
this.context.router.history.push('/');
}
}
};
render () {
return (

@ -55,39 +55,39 @@ class ColumnHeader extends React.PureComponent {
} else {
this.context.router.history.push('/');
}
}
};
handleToggleClick = (e) => {
e.stopPropagation();
this.setState({ collapsed: !this.state.collapsed, animating: true });
}
};
handleTitleClick = () => {
this.props.onClick?.();
}
};
handleMoveLeft = () => {
this.props.onMove(-1);
}
};
handleMoveRight = () => {
this.props.onMove(1);
}
};
handleBackClick = (event) => {
this.historyBack(event.shiftKey);
}
};
handleTransitionEnd = () => {
this.setState({ animating: false });
}
};
handlePin = () => {
if (!this.props.pinned) {
this.historyBack();
}
this.props.onPin();
}
};
render () {
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues } = this.props;

@ -24,7 +24,7 @@ class DismissableBanner extends React.PureComponent {
handleDismiss = () => {
const { id } = this.props;
this.setState({ visible: false }, () => bannerSettings.set(id, true));
}
};
render () {
const { visible } = this.state;

@ -27,7 +27,7 @@ export default class DisplayName extends React.PureComponent {
let emoji = emojis[i];
emoji.src = emoji.getAttribute('data-original');
}
}
};
handleMouseLeave = ({ currentTarget }) => {
if (autoPlayGif) {
@ -40,7 +40,7 @@ export default class DisplayName extends React.PureComponent {
let emoji = emojis[i];
emoji.src = emoji.getAttribute('data-static');
}
}
};
render() {
const { account, className, inline, localDomain, others, onAccountClick } = this.props;
@ -74,7 +74,7 @@ export default class DisplayName extends React.PureComponent {
)).reduce((prev, cur) => [prev, ', ', cur]);
if (others.size - 2 > 0) {
displayName.push(` +${others.size - 2}`);
displayName.push(` +${others.size - 2}`);
}
suffix = (

@ -19,7 +19,7 @@ class Account extends ImmutablePureComponent {
handleDomainUnblock = () => {
this.props.onUnblockDomain(this.props.domain);
}
};
render () {
const { domain, intl } = this.props;

@ -36,7 +36,7 @@ class DropdownMenu extends React.PureComponent {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
}
}
};
componentDidMount () {
document.addEventListener('click', this.handleDocumentClick, false);
@ -56,11 +56,11 @@ class DropdownMenu extends React.PureComponent {
setRef = c => {
this.node = c;
}
};
setFocusRef = c => {
this.focusedItem = c;
}
};
handleKeyDown = e => {
const items = Array.from(this.node.querySelectorAll('a, button'));
@ -97,18 +97,18 @@ class DropdownMenu extends React.PureComponent {
e.preventDefault();
e.stopPropagation();
}
}
};
handleItemKeyPress = e => {
if (e.key === 'Enter' || e.key === ' ') {
this.handleClick(e);
}
}
};
handleClick = e => {
const { onItemClick } = this.props;
onItemClick(e);
}
};
renderItem = (option, i) => {
if (option === null) {
@ -124,7 +124,7 @@ class DropdownMenu extends React.PureComponent {
</a>
</li>
);
}
};
render () {
const { items, scrollable, renderHeader, loading } = this.props;
@ -194,7 +194,7 @@ export default class Dropdown extends React.PureComponent {
} else {
this.props.onOpen(this.state.id, this.handleItemClick, type !== 'click');
}
}
};
handleClose = () => {
if (this.activeElement) {
@ -202,13 +202,13 @@ export default class Dropdown extends React.PureComponent {
this.activeElement = null;
}
this.props.onClose(this.state.id);
}
};
handleMouseDown = () => {
if (!this.state.open) {
this.activeElement = document.activeElement;
}
}
};
handleButtonKeyDown = (e) => {
switch(e.key) {
@ -217,7 +217,7 @@ export default class Dropdown extends React.PureComponent {
this.handleMouseDown();
break;
}
}
};
handleKeyPress = (e) => {
switch(e.key) {
@ -228,7 +228,7 @@ export default class Dropdown extends React.PureComponent {
e.preventDefault();
break;
}
}
};
handleItemClick = e => {
const { onItemClick } = this.props;
@ -247,25 +247,25 @@ export default class Dropdown extends React.PureComponent {
e.preventDefault();
this.context.router.history.push(item.to);
}
}
};
setTargetRef = c => {
this.target = c;
}
};
findTarget = () => {
return this.target;
}
};
componentWillUnmount = () => {
if (this.state.id === this.props.openDropdownId) {
this.handleClose();
}
}
};
close = () => {
this.handleClose();
}
};
render () {
const {

@ -36,7 +36,7 @@ class EditedTimestamp extends React.PureComponent {
return (
<FormattedMessage id='status.edited_x_times' defaultMessage='Edited {count, plural, one {{count} time} other {{count} times}}' values={{ count: items.size - 1 }} />
);
}
};
renderItem = (item, index, { onClick, onKeyPress }) => {
const formattedDate = <RelativeTimestamp timestamp={item.get('created_at')} short={false} />;
@ -53,7 +53,7 @@ class EditedTimestamp extends React.PureComponent {
<button data-index={index} onClick={onClick} onKeyPress={onKeyPress}>{label}</button>
</li>
);
}
};
render () {
const { timestamp, intl, statusId } = this.props;

@ -18,7 +18,7 @@ export default class ErrorBoundary extends React.PureComponent {
stackTrace: undefined,
mappedStackTrace: undefined,
componentStack: undefined,
}
};
componentDidCatch(error, info) {
this.setState({

@ -17,7 +17,7 @@ export default class GIFV extends React.PureComponent {
handleLoadedData = () => {
this.setState({ loading: false });
}
};
componentWillReceiveProps (nextProps) {
if (nextProps.src !== this.props.src) {
@ -32,7 +32,7 @@ export default class GIFV extends React.PureComponent {
e.stopPropagation();
onClick();
}
}
};
render () {
const { src, width, height, alt } = this.props;

@ -46,7 +46,7 @@ export default class IconButton extends React.PureComponent {
state = {
activate: false,
deactivate: false,
}
};
componentWillReceiveProps (nextProps) {
if (!nextProps.animate) return;
@ -64,25 +64,25 @@ export default class IconButton extends React.PureComponent {
if (!this.props.disabled) {
this.props.onClick(e);
}
}
};
handleKeyPress = (e) => {
if (this.props.onKeyPress && !this.props.disabled) {
this.props.onKeyPress(e);
}
}
};
handleMouseDown = (e) => {
if (!this.props.disabled && this.props.onMouseDown) {
this.props.onMouseDown(e);
}
}
};
handleKeyDown = (e) => {
if (!this.props.disabled && this.props.onKeyDown) {
this.props.onKeyDown(e);
}
}
};
render () {
// Hack required for some icons which have an overriden size

@ -21,7 +21,7 @@ export default class IntersectionObserverArticle extends React.Component {
state = {
isHidden: false, // set to true in requestIdleCallback to trigger un-render
}
};
shouldComponentUpdate (nextProps, nextState) {
const isUnrendered = !this.state.isIntersecting && (this.state.isHidden || this.props.cachedHeight);
@ -63,7 +63,7 @@ export default class IntersectionObserverArticle extends React.Component {
scheduleIdleTask(this.calculateHeight);
this.setState(this.updateStateAfterIntersection);
}
};
updateStateAfterIntersection = (prevState) => {
if (prevState.isIntersecting !== false && !this.entry.isIntersecting) {
@ -73,7 +73,7 @@ export default class IntersectionObserverArticle extends React.Component {
isIntersecting: this.entry.isIntersecting,
isHidden: false,
};
}
};
calculateHeight = () => {
const { onHeightChange, saveHeightKey, id } = this.props;
@ -84,7 +84,7 @@ export default class IntersectionObserverArticle extends React.Component {
if (onHeightChange && saveHeightKey) {
onHeightChange(saveHeightKey, id, this.height);
}
}
};
hideIfNotIntersecting = () => {
if (!this.componentMounted) {
@ -96,11 +96,11 @@ export default class IntersectionObserverArticle extends React.Component {
// this is to save DOM nodes and avoid using up too much memory.
// See: https://github.com/mastodon/mastodon/issues/2900
this.setState((prevState) => ({ isHidden: !prevState.isIntersecting }));
}
};
handleRef = (node) => {
this.node = node;
}
};
render () {
const { children, id, index, listLength, cachedHeight } = this.props;
@ -121,8 +121,9 @@ export default class IntersectionObserverArticle extends React.Component {
aria-setsize={listLength}
data-id={id}
tabIndex='0'
style={style}>
{children && React.cloneElement(children, { hidden: !isIntersecting && (isHidden || !!cachedHeight) })}
style={style}
>
{children && React.cloneElement(children, { hidden: !isIntersecting && (isHidden || !!cachedHeight) })}
</article>
);
}

@ -19,7 +19,7 @@ class LoadGap extends React.PureComponent {
handleClick = () => {
this.props.onClick(this.props.maxId);
}
};
render () {
const { disabled, intl } = this.props;

@ -8,11 +8,11 @@ export default class LoadMore extends React.PureComponent {
onClick: PropTypes.func,
disabled: PropTypes.bool,
visible: PropTypes.bool,
}
};
static defaultProps = {
visible: true,
}
};
render() {
const { disabled, visible } = this.props;

@ -7,7 +7,7 @@ export default class LoadPending extends React.PureComponent {
static propTypes = {
onClick: PropTypes.func,
count: PropTypes.number,
}
};
render() {
const { count } = this.props;

@ -30,7 +30,7 @@ export default class MediaAttachments extends ImmutablePureComponent {
return (
<div className='media-gallery' style={{ height, width }} />
);
}
};
renderLoadingVideoPlayer = () => {
const { height, width } = this.props;
@ -38,7 +38,7 @@ export default class MediaAttachments extends ImmutablePureComponent {
return (
<div className='video-player' style={{ height, width }} />
);
}
};
renderLoadingAudioPlayer = () => {
const { height, width } = this.props;
@ -46,7 +46,7 @@ export default class MediaAttachments extends ImmutablePureComponent {
return (
<div className='audio-player' style={{ height, width }} />
);
}
};
render () {
const { status, width, height, revealed } = this.props;

@ -60,14 +60,14 @@ class Item extends React.PureComponent {
if (this.hoverToPlay()) {
e.target.play();
}
}
};
handleMouseLeave = (e) => {
if (this.hoverToPlay()) {
e.target.pause();
e.target.currentTime = 0;
}
}
};
getAutoPlay() {
return this.props.autoplay || autoPlayGif;
@ -91,11 +91,11 @@ class Item extends React.PureComponent {
}
e.stopPropagation();
}
};
handleImageLoad = () => {
this.setState({ loaded: true });
}
};
render () {
const { attachment, index, size, standalone, letterbox, displayWidth, visible } = this.props;
@ -300,11 +300,11 @@ class MediaGallery extends React.PureComponent {
} else {
this.setState({ visible: !this.state.visible });
}
}
};
handleClick = (index) => {
this.props.onOpenMedia(this.props.media, index);
}
};
handleRef = (node) => {
this.node = node;
@ -312,11 +312,11 @@ class MediaGallery extends React.PureComponent {
if (this.node) {
this._setDimensions();
}
}
};
_setDimensions () {
const width = this.node.offsetWidth;
if (width && width != this.state.width) {
// offsetWidth triggers a layout, so only calculate when we need to
if (this.props.cacheWidth) {
@ -353,7 +353,7 @@ class MediaGallery extends React.PureComponent {
} else if (width) {
style.height = width / (16/9);
} else {
return (<div className={computedClass} ref={this.handleRef}></div>);
return (<div className={computedClass} ref={this.handleRef} />);
}
if (this.isStandaloneEligible()) {

@ -5,6 +5,7 @@ import { createBrowserHistory } from 'history';
import { multiply } from 'color-blend';
export default class ModalRoot extends React.PureComponent {
static contextTypes = {
router: PropTypes.object,
};
@ -28,7 +29,7 @@ export default class ModalRoot extends React.PureComponent {
&& !!this.props.children && !this.props.noEsc) {
this.props.onClose();
}
}
};
handleKeyDown = (e) => {
if (e.key === 'Tab') {
@ -49,7 +50,7 @@ export default class ModalRoot extends React.PureComponent {
e.preventDefault();
}
}
}
};
componentDidMount () {
window.addEventListener('keyup', this.handleKeyUp, false);
@ -125,11 +126,11 @@ export default class ModalRoot extends React.PureComponent {
getSiblings = () => {
return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node);
}
};
setRef = ref => {
this.node = ref;
}
};
render () {
const { children, onClose } = this.props;

@ -24,12 +24,12 @@ export default class Permalink extends React.PureComponent {
if (this.context.router) {
e.preventDefault();
let state = {...this.context.router.history.location.state};
let state = { ...this.context.router.history.location.state };
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
this.context.router.history.push(this.props.to, state);
}
}
}
};
render () {
const {

@ -22,7 +22,7 @@ class PictureInPicturePlaceholder extends React.PureComponent {
handleClick = () => {
const { dispatch } = this.props;
dispatch(removePictureInPicture());
}
};
setRef = c => {
this.node = c;
@ -30,7 +30,7 @@ class PictureInPicturePlaceholder extends React.PureComponent {
if (this.node) {
this._setDimensions();
}
}
};
_setDimensions () {
const width = this.node.offsetWidth;

@ -95,7 +95,7 @@ class Poll extends ImmutablePureComponent {
tmp[value] = true;
this.setState({ selected: tmp });
}
}
};
handleOptionChange = ({ target: { value } }) => {
this._toggleOption(value);
@ -107,7 +107,7 @@ class Poll extends ImmutablePureComponent {
e.stopPropagation();
e.preventDefault();
}
}
};
handleVote = () => {
if (this.props.disabled) {

@ -137,7 +137,7 @@ class ScrollableList extends PureComponent {
}
this.mouseMovedRecently = false;
this.scrollToTopOnMouseIdle = false;
}
};
componentDidMount () {
this.attachScrollListener();
@ -154,29 +154,29 @@ class ScrollableList extends PureComponent {
} else {
return null;
}
}
};
getScrollTop = () => {
return this.props.bindToDocument ? document.scrollingElement.scrollTop : this.node.scrollTop;
}
};
getScrollHeight = () => {
return this.props.bindToDocument ? document.scrollingElement.scrollHeight : this.node.scrollHeight;
}
};
getClientHeight = () => {
return this.props.bindToDocument ? document.scrollingElement.clientHeight : this.node.clientHeight;
}
};
updateScrollBottom = (snapshot) => {
const newScrollTop = this.getScrollHeight() - snapshot;
this.setScrollTop(newScrollTop);
}
};
cacheMediaWidth = (width) => {
if (width && this.state.cachedMediaWidth != width) this.setState({ cachedMediaWidth: width });
}
};
getSnapshotBeforeUpdate (prevProps, prevState) {
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
@ -208,7 +208,7 @@ class ScrollableList extends PureComponent {
onFullScreenChange = () => {
this.setState({ fullscreen: isFullscreen() });
}
};
attachIntersectionObserver () {
this.intersectionObserverWrapper.connect({
@ -256,12 +256,12 @@ class ScrollableList extends PureComponent {
setRef = (c) => {
this.node = c;
}
};
handleLoadMore = e => {
e.preventDefault();
this.props.onLoadMore();
}
};
handleLoadPending = e => {
e.preventDefault();
@ -273,7 +273,7 @@ class ScrollableList extends PureComponent {
this.clearMouseIdleTimer();
this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);
this.mouseMovedRecently = true;
}
};
render () {
const { children, scrollKey, trackScroll, showLoading, isLoading, hasMore, numPending, prepend, alwaysPrepend, append, emptyMessage, onLoadMore } = this.props;

@ -13,7 +13,7 @@ export default class SettingText extends React.PureComponent {
handleChange = (e) => {
this.props.onChange(this.props.settingPath, e.target.value);
}
};
render () {
const { settings, settingPath, label } = this.props;

@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl';
export default
class Spoilers extends React.PureComponent {
static propTypes = {
spoilerText: PropTypes.string,
children: PropTypes.node,
@ -11,27 +12,27 @@ class Spoilers extends React.PureComponent {
state = {
hidden: true,
}
};
handleSpoilerClick = () => {
this.setState({ hidden: !this.state.hidden });
}
};
render () {
const { spoilerText, children } = this.props;
const { hidden } = this.state;
const toggleText = hidden ?
<FormattedMessage
id='status.show_more'
defaultMessage='Show more'
key='0'
/> :
<FormattedMessage
id='status.show_less'
defaultMessage='Show less'
key='0'
/>;
const toggleText = hidden ?
(<FormattedMessage
id='status.show_more'
defaultMessage='Show more'
key='0'
/>) :
(<FormattedMessage
id='status.show_less'
defaultMessage='Show less'
key='0'
/>);
return ([
<p className='spoiler__text'>
@ -43,8 +44,9 @@ class Spoilers extends React.PureComponent {
</p>,
<div className={`status__content__spoiler ${!hidden ? 'status__content__spoiler--visible' : ''}`}>
{children}
</div>
</div>,
]);
}
}

@ -54,7 +54,7 @@ export const defaultMediaVisibility = (status, settings) => {
}
return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all');
}
};
export default @injectIntl
class Status extends ImmutablePureComponent {
@ -117,7 +117,7 @@ class Status extends ImmutablePureComponent {
revealBehindCW: undefined,
showCard: false,
forceFilter: undefined,
}
};
// Avoid checking props that are functions (and whose equality will always
// evaluate to false. See react-immutable-pure-component for usage.
@ -132,14 +132,14 @@ class Status extends ImmutablePureComponent {
'expanded',
'unread',
'pictureInPicture',
]
];
updateOnStates = [
'isExpanded',
'isCollapsed',
'showMedia',
'forceFilter',
]
];
// If our settings have changed to disable collapsed statuses, then we
// need to make sure that we uncollapse every one. We do that by watching
@ -302,7 +302,9 @@ class Status extends ImmutablePureComponent {
if (this.node && this.props.getScrollPosition) {
const position = this.props.getScrollPosition();
if (position !== null && this.node.offsetTop < position.top) {
requestAnimationFrame(() => { this.props.updateScrollBottom(position.height - position.top); });
requestAnimationFrame(() => {
this.props.updateScrollBottom(position.height - position.top);
});
}
}
}
@ -321,7 +323,7 @@ class Status extends ImmutablePureComponent {
} else {
this.setState({ isCollapsed: false });
}
}
};
setExpansion = (value) => {
if (this.props.settings.getIn(['content_warnings', 'shared_state']) && this.props.status.get('hidden') === value) {
@ -332,7 +334,7 @@ class Status extends ImmutablePureComponent {
if (value) {
this.setCollapsed(false);
}
}
};
// `parseClick()` takes a click event and responds appropriately.
// If our status is collapsed, then clicking on it should uncollapse it.
@ -361,17 +363,17 @@ class Status extends ImmutablePureComponent {
status.getIn(['reblog', 'id'], status.get('id'))
}`;
}
let state = {...router.history.location.state};
let state = { ...router.history.location.state };
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
router.history.push(destination, state);
}
e.preventDefault();
}
}
};
handleToggleMediaVisibility = () => {
this.setState({ showMedia: !this.state.showMedia });
}
};
handleExpandedToggle = () => {
if (this.props.settings.getIn(['content_warnings', 'shared_state'])) {
@ -384,11 +386,11 @@ class Status extends ImmutablePureComponent {
handleOpenVideo = (options) => {
const { status } = this.props;
this.props.onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), options);
}
};
handleOpenMedia = (media, index) => {
this.props.onOpenMedia(this.props.status.get('id'), media, index);
}
};
handleHotkeyOpenMedia = e => {
const { status, onOpenMedia, onOpenVideo } = this.props;
@ -403,84 +405,84 @@ class Status extends ImmutablePureComponent {
onOpenMedia(statusId, status.get('media_attachments'), 0);
}
}
}
};
handleDeployPictureInPicture = (type, mediaProps) => {
const { deployPictureInPicture, status } = this.props;
deployPictureInPicture(status, type, mediaProps);
}
};
handleHotkeyReply = e => {
e.preventDefault();
this.props.onReply(this.props.status, this.context.router.history);
}
};
handleHotkeyFavourite = (e) => {
this.props.onFavourite(this.props.status, e);
}
};
handleHotkeyBoost = e => {
this.props.onReblog(this.props.status, e);
}
};
handleHotkeyBookmark = e => {
this.props.onBookmark(this.props.status, e);
}
};
handleHotkeyMention = e => {
e.preventDefault();
this.props.onMention(this.props.status.get('account'), this.context.router.history);
}
};
handleHotkeyOpen = () => {
let state = {...this.context.router.history.location.state};
let state = { ...this.context.router.history.location.state };
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
const status = this.props.status;
this.context.router.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`, state);
}
};
handleHotkeyOpenProfile = () => {
let state = {...this.context.router.history.location.state};
let state = { ...this.context.router.history.location.state };
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`, state);
}
};
handleHotkeyMoveUp = e => {
this.props.onMoveUp(this.props.containerId || this.props.id, e.target.getAttribute('data-featured'));
}
};
handleHotkeyMoveDown = e => {
this.props.onMoveDown(this.props.containerId || this.props.id, e.target.getAttribute('data-featured'));
}
};
handleHotkeyCollapse = e => {
if (!this.props.settings.getIn(['collapsed', 'enabled']))
return;
this.setCollapsed(!this.state.isCollapsed);
}
};
handleHotkeyToggleSensitive = () => {
this.handleToggleMediaVisibility();
}
};
handleUnfilterClick = e => {
this.setState({ forceFilter: false });
e.preventDefault();
}
};
handleFilterClick = () => {
this.setState({ forceFilter: true });
}
};
handleRef = c => {
this.node = c;
}
};
handleTranslate = () => {
this.props.onTranslate(this.props.status);
}
};
renderLoadingMediaGallery () {
return <div className='media-gallery' style={{ height: '110px' }} />;

@ -86,7 +86,7 @@ class StatusActionBar extends ImmutablePureComponent {
'showReplyCount',
'withCounters',
'withDismiss',
]
];
handleReplyClick = () => {
const { signedIn } = this.context.identity;
@ -96,14 +96,14 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
this.props.onInteractionModal('reply', this.props.status);
}
}
};
handleShareClick = () => {
navigator.share({
text: this.props.status.get('search_index'),
url: this.props.status.get('url'),
});
}
};
handleFavouriteClick = (e) => {
const { signedIn } = this.context.identity;
@ -113,7 +113,7 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
this.props.onInteractionModal('favourite', this.props.status);
}
}
};
handleReblogClick = e => {
const { signedIn } = this.context.identity;
@ -123,78 +123,78 @@ class StatusActionBar extends ImmutablePureComponent {
} else {
this.props.onInteractionModal('reblog', this.props.status);
}
}
};
handleBookmarkClick = (e) => {
this.props.onBookmark(this.props.status, e);
}
};
handleDeleteClick = () => {
this.props.onDelete(this.props.status, this.context.router.history);
}
};
handleRedraftClick = () => {
this.props.onDelete(this.props.status, this.context.router.history, true);
}
};
handleEditClick = () => {
this.props.onEdit(this.props.status, this.context.router.history);
}
};
handlePinClick = () => {
this.props.onPin(this.props.status);
}
};
handleMentionClick = () => {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
}
};
handleDirectClick = () => {
this.props.onDirect(this.props.status.get('account'), this.context.router.history);
}
};
handleMuteClick = () => {
this.props.onMute(this.props.status.get('account'));
}
};
handleBlockClick = () => {
this.props.onBlock(this.props.status);
}
};
handleOpen = () => {
let state = {...this.context.router.history.location.state};
let state = { ...this.context.router.history.location.state };
if (state.mastodonModalKey) {
this.context.router.history.replace(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`, { mastodonBackSteps: (state.mastodonBackSteps || 0) + 1 });
} else {
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`, state);
}
}
};
handleEmbed = () => {
this.props.onEmbed(this.props.status);
}
};
handleReport = () => {
this.props.onReport(this.props.status);
}
};
handleConversationMuteClick = () => {
this.props.onMuteConversation(this.props.status);
}
};
handleCopy = () => {
const url = this.props.status.get('url');
navigator.clipboard.writeText(url);
}
};
handleHideClick = () => {
this.props.onFilter();
}
};
handleFilterClick = () => {
this.props.onAddFilter(this.props.status);
}
};
render () {
const { status, intl, withDismiss, withCounters, showReplyCount, scrollKey } = this.props;

@ -12,7 +12,7 @@ const textMatchesTarget = (text, origin, host) => {
return (text === origin || text === host
|| text.startsWith(origin + '/') || text.startsWith(host + '/')
|| 'www.' + text === host || ('www.' + text).startsWith(host + '/'));
}
};
const isLinkMisleading = (link) => {
let linkTextParts = [];
@ -168,8 +168,8 @@ class StatusContent extends React.PureComponent {
link.setAttribute('title', link.href);
link.classList.add('unhandled-link');
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener nofollow noreferrer');
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener nofollow noreferrer');
try {
if (tagLinks && isLinkMisleading(link)) {
@ -210,7 +210,7 @@ class StatusContent extends React.PureComponent {
let emoji = emojis[i];
emoji.src = emoji.getAttribute('data-original');
}
}
};
handleMouseLeave = ({ currentTarget }) => {
if (autoPlayGif) {
@ -223,7 +223,7 @@ class StatusContent extends React.PureComponent {
let emoji = emojis[i];
emoji.src = emoji.getAttribute('data-static');
}
}
};
componentDidMount () {
this._updateStatusLinks();
@ -238,13 +238,13 @@ class StatusContent extends React.PureComponent {
if (this.props.collapsed) {
if (this.props.parseClick) this.props.parseClick(e);
}
}
};
onMentionClick = (mention, e) => {
if (this.props.parseClick) {
this.props.parseClick(e, `/@${mention.get('acct')}`);
}
}
};
onHashtagClick = (hashtag, e) => {
hashtag = hashtag.replace(/^#/, '');
@ -252,11 +252,11 @@ class StatusContent extends React.PureComponent {
if (this.props.parseClick) {
this.props.parseClick(e, `/tags/${hashtag}`);
}
}
};
handleMouseDown = (e) => {
this.startXY = [e.clientX, e.clientY];
}
};
handleMouseUp = (e) => {
const { parseClick, disabled } = this.props;
@ -281,7 +281,7 @@ class StatusContent extends React.PureComponent {
}
this.startXY = null;
}
};
handleSpoilerClick = (e) => {
e.preventDefault();
@ -291,15 +291,15 @@ class StatusContent extends React.PureComponent {
} else {
this.setState({ hidden: !this.state.hidden });
}
}
};
handleTranslate = () => {
this.props.onTranslate();
}
};
setContentsRef = (c) => {
this.contentsNode = c;
}
};
render () {
const {

@ -21,12 +21,12 @@ export default class StatusHeader extends React.PureComponent {
handleClick = (acct, e) => {
const { parseClick } = this.props;
parseClick(e, `/@${acct}`);
}
};
handleAccountClick = (e) => {
const { status } = this.props;
this.handleClick(status.getIn(['account', 'acct']), e);
}
};
// Rendering.
render () {

@ -60,22 +60,22 @@ class StatusIcons extends React.PureComponent {
setCollapsed(!collapsed);
e.preventDefault();
}
}
};
mediaIconTitleText (mediaIcon) {
const { intl } = this.props;
switch (mediaIcon) {
case 'link':
return intl.formatMessage(messages.previewCard);
case 'picture-o':
return intl.formatMessage(messages.pictures);
case 'tasks':
return intl.formatMessage(messages.poll);
case 'video-camera':
return intl.formatMessage(messages.video);
case 'music':
return intl.formatMessage(messages.audio);
case 'link':
return intl.formatMessage(messages.previewCard);
case 'picture-o':
return intl.formatMessage(messages.pictures);
case 'tasks':
return intl.formatMessage(messages.poll);
case 'video-camera':
return intl.formatMessage(messages.video);
case 'music':
return intl.formatMessage(messages.audio);
}
}

@ -35,7 +35,7 @@ export default class StatusList extends ImmutablePureComponent {
getFeaturedStatusCount = () => {
return this.props.featuredStatusIds ? this.props.featuredStatusIds.size : 0;
}
};
getCurrentStatusIndex = (id, featured) => {
if (featured) {
@ -43,21 +43,21 @@ export default class StatusList extends ImmutablePureComponent {
} else {
return this.props.statusIds.indexOf(id) + this.getFeaturedStatusCount();
}
}
};
handleMoveUp = (id, featured) => {
const elementIndex = this.getCurrentStatusIndex(id, featured) - 1;
this._selectChild(elementIndex, true);
}
};
handleMoveDown = (id, featured) => {
const elementIndex = this.getCurrentStatusIndex(id, featured) + 1;
this._selectChild(elementIndex, false);
}
};
handleLoadOlder = debounce(() => {
this.props.onLoadMore(this.props.statusIds.size > 0 ? this.props.statusIds.last() : undefined);
}, 300, { leading: true })
}, 300, { leading: true });
_selectChild (index, align_top) {
const container = this.node.node;
@ -75,7 +75,7 @@ export default class StatusList extends ImmutablePureComponent {
setRef = c => {
this.node = c;
}
};
render () {
const { statusIds, featuredStatusIds, onLoadMore, timelineId, ...other } = this.props;

@ -18,7 +18,7 @@ export default class StatusPrepend extends React.PureComponent {
handleClick = (e) => {
const { account, parseClick } = this.props;
parseClick(e, `/@${account.get('acct')}`);
}
};
Message = () => {
const { type, account } = this.props;
@ -98,7 +98,7 @@ export default class StatusPrepend extends React.PureComponent {
);
}
return null;
}
};
render () {
const { Message } = this;
@ -126,7 +126,7 @@ export default class StatusPrepend extends React.PureComponent {
case 'update':
iconId = 'pencil';
break;
};
}
return !type ? null : (
<aside className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend' : 'notification__message'}>

@ -39,7 +39,7 @@ export default class MediaContainer extends PureComponent {
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
this.setState({ media, index });
}
};
handleOpenVideo = (options) => {
const { components } = this.props;
@ -50,7 +50,7 @@ export default class MediaContainer extends PureComponent {
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
this.setState({ media: mediaList, options });
}
};
handleCloseMedia = () => {
document.body.classList.remove('with-modals--active');
@ -63,11 +63,11 @@ export default class MediaContainer extends PureComponent {
backgroundColor: null,
options: null,
});
}
};
setBackgroundColor = color => {
this.setState({ backgroundColor: color });
}
};
render () {
const { locale, components } = this.props;

@ -1,3 +1,2 @@
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
import 'intersection-observer';
import 'requestidlecallback';

@ -59,7 +59,7 @@ class Section extends React.PureComponent {
const { collapsed } = this.state;
this.setState({ collapsed: !collapsed }, () => onOpen && onOpen());
}
};
render () {
const { title, children } = this.props;
@ -106,7 +106,7 @@ class About extends React.PureComponent {
handleDomainBlocksOpen = () => {
const { dispatch } = this.props;
dispatch(fetchDomainBlocks());
}
};
render () {
const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props;

@ -41,7 +41,7 @@ class Header extends ImmutablePureComponent {
} else if (e.keyCode === 27) {
this.props.onCancelAccountNote();
}
}
};
render () {
const { account, accountNote, isEditing, isSubmitting, intl } = this.props;

@ -21,7 +21,7 @@ class ActionBar extends React.PureComponent {
return false;
}
return !location.pathname.match(/\/(followers|following)\/?$/);
}
};
render () {
const { account, intl } = this.props;
@ -32,7 +32,7 @@ class ActionBar extends React.PureComponent {
<div className='account__disclaimer'>
<Icon id='info-circle' fixedWidth /> <FormattedMessage
id='account.suspended_disclaimer_full'
defaultMessage="This user has been suspended by a moderator."
defaultMessage='This user has been suspended by a moderator.'
/>
</div>
</div>

@ -109,7 +109,7 @@ class Header extends ImmutablePureComponent {
openEditProfile = () => {
window.open(profileLink, '_blank');
}
};
handleMouseEnter = ({ currentTarget }) => {
if (autoPlayGif) {
@ -122,7 +122,7 @@ class Header extends ImmutablePureComponent {
let emoji = emojis[i];
emoji.src = emoji.getAttribute('data-original');
}
}
};
handleMouseLeave = ({ currentTarget }) => {
if (autoPlayGif) {
@ -135,14 +135,14 @@ class Header extends ImmutablePureComponent {
let emoji = emojis[i];
emoji.src = emoji.getAttribute('data-static');
}
}
};
handleAvatarClick = e => {
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
this.props.onOpenAvatar();
}
}
};
handleShare = () => {
const { account } = this.props;
@ -153,7 +153,7 @@ class Header extends ImmutablePureComponent {
}).catch((e) => {
if (e.name !== 'AbortError') console.error(e);
});
}
};
render () {
const { account, hidden, intl, domain } = this.props;
@ -177,8 +177,7 @@ class Header extends ImmutablePureComponent {
if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
info.push(<span className='relationship-tag'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>);
}
else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
} else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
info.push(<span className='relationship-tag'><FormattedMessage id='account.blocked' defaultMessage='Blocked' /></span>);
}
@ -378,7 +377,7 @@ class Header extends ImmutablePureComponent {
{fields.map((pair, i) => (
<dl key={i}>
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} className='translate' />
</dd>

@ -22,20 +22,20 @@ export default class MediaItem extends ImmutablePureComponent {
handleImageLoad = () => {
this.setState({ loaded: true });
}
};
handleMouseEnter = e => {
if (this.hoverToPlay()) {
e.target.play();
}
}
};
handleMouseLeave = e => {
if (this.hoverToPlay()) {
e.target.pause();
e.target.currentTime = 0;
}
}
};
hoverToPlay () {
return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1;
@ -51,7 +51,7 @@ export default class MediaItem extends ImmutablePureComponent {
this.setState({ visible: true });
}
}
}
};
render () {
const { attachment, displayWidth } = this.props;

@ -45,7 +45,7 @@ class LoadMoreMedia extends ImmutablePureComponent {
handleLoadMore = () => {
this.props.onLoadMore(this.props.maxId);
}
};
render () {
return (
@ -109,13 +109,13 @@ class AccountGallery extends ImmutablePureComponent {
handleHeaderClick = () => {
this.column.scrollTop();
}
};
handleScrollToBottom = () => {
if (this.props.hasMore) {
this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(['status', 'id']) : undefined);
}
}
};
handleScroll = e => {
const { scrollTop, scrollHeight, clientHeight } = e.target;
@ -124,7 +124,7 @@ class AccountGallery extends ImmutablePureComponent {
if (150 > offset && !this.props.isLoading) {
this.handleScrollToBottom();
}
}
};
handleLoadMore = maxId => {
this.props.dispatch(expandAccountMediaTimeline(this.props.accountId, { maxId }));
@ -133,11 +133,11 @@ class AccountGallery extends ImmutablePureComponent {
handleLoadOlder = e => {
e.preventDefault();
this.handleScrollToBottom();
}
};
setColumnRef = c => {
this.column = c;
}
};
handleOpenMedia = attachment => {
const { dispatch } = this.props;
@ -153,13 +153,13 @@ class AccountGallery extends ImmutablePureComponent {
dispatch(openModal('MEDIA', { media, index, statusId }));
}
}
};
handleRef = c => {
if (c) {
this.setState({ width: c.offsetWidth });
}
}
};
render () {
const { attachments, isLoading, hasMore, isAccount, multiColumn, suspended } = this.props;

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

Loading…
Cancel
Save