From 5cbc402687a99511b8fa20b1541a774c0428be16 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 11:30:53 +0200 Subject: [PATCH 01/34] Fix replica being used even if not explicitly defined (#26074) --- app/models/application_record.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 23e0af3a2a..efff5cdad5 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -5,7 +5,7 @@ class ApplicationRecord < ActiveRecord::Base include Remotable - connects_to database: { writing: :primary, reading: :read } + connects_to database: { writing: :primary, reading: ENV['DB_REPLICA_NAME'] || ENV['READ_DATABASE_URL'] ? :read : :primary } class << self def update_index(_type_name, *_args, &_block) From 144a406d332b034caa812ade2629df03ed4898d7 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 13:13:16 +0200 Subject: [PATCH 02/34] Clean up unused application records (#24871) --- .rubocop_todo.yml | 1 + app/lib/application_extension.rb | 2 + app/lib/vacuum/applications_vacuum.rb | 10 +++++ app/workers/scheduler/vacuum_scheduler.rb | 5 +++ spec/lib/vacuum/applications_vacuum_spec.rb | 48 +++++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 app/lib/vacuum/applications_vacuum.rb create mode 100644 spec/lib/vacuum/applications_vacuum_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 32fb99b772..71e8623ec5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -289,6 +289,7 @@ RSpec/LetSetup: - 'spec/controllers/oauth/tokens_controller_spec.rb' - 'spec/controllers/settings/imports_controller_spec.rb' - 'spec/lib/activitypub/activity/delete_spec.rb' + - 'spec/lib/vacuum/applications_vacuum_spec.rb' - 'spec/lib/vacuum/preview_cards_vacuum_spec.rb' - 'spec/models/account_spec.rb' - 'spec/models/account_statuses_cleanup_policy_spec.rb' diff --git a/app/lib/application_extension.rb b/app/lib/application_extension.rb index 4de69c1ead..fb442e2c2d 100644 --- a/app/lib/application_extension.rb +++ b/app/lib/application_extension.rb @@ -4,6 +4,8 @@ module ApplicationExtension extend ActiveSupport::Concern included do + has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application + validates :name, length: { maximum: 60 } validates :website, url: true, length: { maximum: 2_000 }, if: :website? validates :redirect_uri, length: { maximum: 2_000 } diff --git a/app/lib/vacuum/applications_vacuum.rb b/app/lib/vacuum/applications_vacuum.rb new file mode 100644 index 0000000000..ba88655f16 --- /dev/null +++ b/app/lib/vacuum/applications_vacuum.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Vacuum::ApplicationsVacuum + def perform + Doorkeeper::Application.where(owner_id: nil) + .where.missing(:created_users, :access_tokens, :access_grants) + .where(created_at: ...1.day.ago) + .in_batches.delete_all + end +end diff --git a/app/workers/scheduler/vacuum_scheduler.rb b/app/workers/scheduler/vacuum_scheduler.rb index 9e884caefd..9c040f6e47 100644 --- a/app/workers/scheduler/vacuum_scheduler.rb +++ b/app/workers/scheduler/vacuum_scheduler.rb @@ -22,6 +22,7 @@ class Scheduler::VacuumScheduler preview_cards_vacuum, backups_vacuum, access_tokens_vacuum, + applications_vacuum, feeds_vacuum, imports_vacuum, ] @@ -55,6 +56,10 @@ class Scheduler::VacuumScheduler Vacuum::ImportsVacuum.new end + def applications_vacuum + Vacuum::ApplicationsVacuum.new + end + def content_retention_policy ContentRetentionPolicy.current end diff --git a/spec/lib/vacuum/applications_vacuum_spec.rb b/spec/lib/vacuum/applications_vacuum_spec.rb new file mode 100644 index 0000000000..d30311ab13 --- /dev/null +++ b/spec/lib/vacuum/applications_vacuum_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Vacuum::ApplicationsVacuum do + subject { described_class.new } + + describe '#perform' do + let!(:app1) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app2) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app3) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app4) { Fabricate(:application, created_at: 1.month.ago, owner: Fabricate(:user)) } + let!(:app5) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app6) { Fabricate(:application, created_at: 1.hour.ago) } + + let!(:active_access_token) { Fabricate(:access_token, application: app1) } + let!(:active_access_grant) { Fabricate(:access_grant, application: app2) } + let!(:user) { Fabricate(:user, created_by_application: app3) } + + before do + subject.perform + end + + it 'does not delete applications with valid access tokens' do + expect { app1.reload }.to_not raise_error + end + + it 'does not delete applications with valid access grants' do + expect { app2.reload }.to_not raise_error + end + + it 'does not delete applications that were used to create users' do + expect { app3.reload }.to_not raise_error + end + + it 'does not delete owned applications' do + expect { app4.reload }.to_not raise_error + end + + it 'does not delete applications registered less than a day ago' do + expect { app6.reload }.to_not raise_error + end + + it 'deletes unused applications' do + expect { app5.reload }.to raise_error ActiveRecord::RecordNotFound + end + end +end From e4ea80d8089110790bf11f7d4021dbe7b6a866de Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 13:14:30 +0200 Subject: [PATCH 03/34] Change thread view to scroll to the selected post rather than the post being replied to (#24685) --- .../mastodon/features/status/index.jsx | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index e5f91071e9..4f58c7d2fd 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -196,8 +196,8 @@ class Status extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, status: ImmutablePropTypes.map, isLoading: PropTypes.bool, - ancestorsIds: ImmutablePropTypes.list, - descendantsIds: ImmutablePropTypes.list, + ancestorsIds: ImmutablePropTypes.list.isRequired, + descendantsIds: ImmutablePropTypes.list.isRequired, intl: PropTypes.object.isRequired, askReplyConfirmation: PropTypes.bool, multiColumn: PropTypes.bool, @@ -224,14 +224,9 @@ class Status extends ImmutablePureComponent { UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { - this._scrolledIntoView = false; this.props.dispatch(fetchStatus(nextProps.params.statusId)); } - if (nextProps.params.statusId && nextProps.ancestorsIds.size > this.props.ancestorsIds.size) { - this._scrolledIntoView = false; - } - if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) { this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get('id') }); } @@ -584,20 +579,23 @@ class Status extends ImmutablePureComponent { this.node = c; }; - componentDidUpdate () { - if (this._scrolledIntoView) { - return; - } - - const { status, ancestorsIds } = this.props; - - if (status && ancestorsIds && ancestorsIds.size > 0) { - const element = this.node.querySelectorAll('.focusable')[ancestorsIds.size - 1]; + componentDidUpdate (prevProps) { + const { status, ancestorsIds, multiColumn } = this.props; + if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) { window.requestAnimationFrame(() => { - element.scrollIntoView(true); + this.node?.querySelector('.detailed-status__wrapper')?.scrollIntoView(true); + + // In the single-column interface, `scrollIntoView` will put the post behind the header, + // so compensate for that. + if (!multiColumn) { + const offset = document.querySelector('.column-header__wrapper')?.getBoundingClientRect()?.bottom; + if (offset) { + const scrollingElement = document.scrollingElement || document.body; + scrollingElement.scrollBy(0, -offset); + } + } }); - this._scrolledIntoView = true; } } From 934c7b33d1d33e3e12a7bb12f654b5d8eed0d51b Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 13:17:43 +0200 Subject: [PATCH 04/34] Change default KeyGenerator digest to SHA1 to fix cookies in rolling upgrades (#26023) --- config/initializers/cookie_rotator.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/initializers/cookie_rotator.rb b/config/initializers/cookie_rotator.rb index 349c363f14..b829b1a90b 100644 --- a/config/initializers/cookie_rotator.rb +++ b/config/initializers/cookie_rotator.rb @@ -1,5 +1,10 @@ # frozen_string_literal: true +# TODO: Remove after 4.2.0 +Rails.application.configure do + config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA1 +end + Rails.application.config.after_initialize do Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies| authenticated_encrypted_cookie_salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt @@ -7,8 +12,9 @@ Rails.application.config.after_initialize do secret_key_base = Rails.application.secret_key_base + # TODO: Switch to SHA1 after 4.2.0 key_generator = ActiveSupport::KeyGenerator.new( - secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1 + secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA256 ) key_len = ActiveSupport::MessageEncryptor.key_len From 59478a1b46e934c75ad27f1270d9b9411de3f185 Mon Sep 17 00:00:00 2001 From: Trevor Wolf Date: Fri, 21 Jul 2023 21:20:14 +1000 Subject: [PATCH 05/34] change focus ui for keyboard only input (#25935) --- .../mastodon/components/dropdown_menu.jsx | 2 +- .../compose/components/navigation_bar.jsx | 19 +++-- app/javascript/styles/mastodon/basics.scss | 15 +++- .../styles/mastodon/components.scss | 83 +++++-------------- app/javascript/styles/mastodon/variables.scss | 4 + 5 files changed, 50 insertions(+), 73 deletions(-) diff --git a/app/javascript/mastodon/components/dropdown_menu.jsx b/app/javascript/mastodon/components/dropdown_menu.jsx index 0416df5d45..fd66310e85 100644 --- a/app/javascript/mastodon/components/dropdown_menu.jsx +++ b/app/javascript/mastodon/components/dropdown_menu.jsx @@ -297,7 +297,7 @@ export default class Dropdown extends PureComponent { onKeyPress: this.handleKeyPress, }) : ( - - {this.props.account.get('acct')} + + {username}
- - @{this.props.account.get('acct')} - + + + @{username} + + - + + +
-
diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss index ff00c797c8..234c703f23 100644 --- a/app/javascript/styles/mastodon/basics.scss +++ b/app/javascript/styles/mastodon/basics.scss @@ -161,13 +161,20 @@ body { } } +a { + &:focus { + border-radius: 4px; + outline: $ui-button-icon-focus-outline; + } + + &:focus:not(:focus-visible) { + outline: none; + } +} + button { font-family: inherit; cursor: pointer; - - &:focus { - outline: none; - } } .app-holder { diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index beff07daa4..d08cb28038 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -74,6 +74,10 @@ background-color: $ui-button-focus-background-color; } + &:focus { + outline: $ui-button-icon-focus-outline; + } + &--destructive { &:active, &:focus, @@ -98,16 +102,6 @@ transition: none; } - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - &.button-secondary { color: $ui-button-secondary-color; background: transparent; @@ -197,7 +191,7 @@ border-radius: 4px; background: transparent; cursor: pointer; - transition: all 100ms ease-in; + transition: all 100ms ease-out; transition-property: background-color, color; text-decoration: none; @@ -209,14 +203,12 @@ &:hover, &:active, &:focus { - color: lighten($action-button-color, 7%); - background-color: rgba($action-button-color, 0.15); - transition: all 200ms ease-out; - transition-property: background-color, color; + color: lighten($action-button-color, 20%); + background-color: $ui-button-icon-hover-background-color; } &:focus { - background-color: rgba($action-button-color, 0.3); + outline: $ui-button-icon-focus-outline; } &.disabled { @@ -225,20 +217,6 @@ cursor: default; } - &.active { - color: $highlight-text-color; - } - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - &.inverted { color: $lighter-text-color; @@ -246,11 +224,11 @@ &:active, &:focus { color: darken($lighter-text-color, 7%); - background-color: rgba($lighter-text-color, 0.15); + background-color: $ui-button-icon-hover-background-color; } &:focus { - background-color: rgba($lighter-text-color, 0.3); + outline: $ui-button-icon-focus-outline; } &.disabled { @@ -305,7 +283,6 @@ font-size: 11px; padding: 0 3px; line-height: 27px; - outline: 0; transition: all 100ms ease-in; transition-property: background-color, color; @@ -313,13 +290,13 @@ &:active, &:focus { color: darken($lighter-text-color, 7%); - background-color: rgba($lighter-text-color, 0.15); + background-color: $ui-button-icon-hover-background-color; transition: all 200ms ease-out; transition-property: background-color, color; } &:focus { - background-color: rgba($lighter-text-color, 0.3); + outline: $ui-button-icon-focus-outline; } &.disabled { @@ -331,16 +308,6 @@ &.active { color: $highlight-text-color; } - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } } body > [data-popper-placement] { @@ -728,7 +695,6 @@ body > [data-popper-placement] { flex: 0 0 auto; .compose-form__publish-button-wrapper { - overflow: hidden; padding-top: 15px; } } @@ -1929,13 +1895,6 @@ a.account__display-name { .navigation-bar__actions { position: relative; - .icon-button.close { - position: absolute; - pointer-events: none; - transform: scale(0, 1) translate(-100%, 0); - opacity: 0; - } - .compose__action-bar .icon-button { pointer-events: auto; transform: scale(1, 1) translate(0, 0); @@ -1945,19 +1904,21 @@ a.account__display-name { } .navigation-bar__profile { + display: flex; + flex-direction: column; flex: 1 1 auto; line-height: 20px; - overflow: hidden; } .navigation-bar__profile-account { - display: block; + display: inline; font-weight: 500; overflow: hidden; text-overflow: ellipsis; } .navigation-bar__profile-edit { + display: inline; color: inherit; text-decoration: none; } @@ -4740,11 +4701,6 @@ a.status-card.compact:hover { outline: 0; cursor: pointer; - &:active, - &:focus { - outline: 0 !important; - } - img { filter: grayscale(100%); opacity: 0.8; @@ -4760,6 +4716,13 @@ a.status-card.compact:hover { img { opacity: 1; filter: none; + border-radius: 100%; + } + } + + &:focus { + img { + outline: $ui-button-icon-focus-outline; } } } diff --git a/app/javascript/styles/mastodon/variables.scss b/app/javascript/styles/mastodon/variables.scss index 68db9d5fc0..e89dd5d3ab 100644 --- a/app/javascript/styles/mastodon/variables.scss +++ b/app/javascript/styles/mastodon/variables.scss @@ -5,6 +5,7 @@ $red-600: #b7253d !default; // Deep Carmine $red-500: #df405a !default; // Cerise $blurple-600: #563acc; // Iris $blurple-500: #6364ff; // Brand purple +$blurple-400: #7477fd; // Medium slate blue $blurple-300: #858afa; // Faded Blue $grey-600: #4e4c5a; // Trout $grey-100: #dadaf3; // Topaz @@ -56,6 +57,9 @@ $ui-button-tertiary-focus-color: $white !default; $ui-button-destructive-background-color: $red-500 !default; $ui-button-destructive-focus-background-color: $red-600 !default; +$ui-button-icon-focus-outline: solid 2px $blurple-400 !default; +$ui-button-icon-hover-background-color: rgba(140, 141, 255, 40%) !default; + // Variables for texts $primary-text-color: $white !default; $darker-text-color: $ui-primary-color !default; From 14fad603845dedda87300516a90d78b3b69133df Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 13:20:53 +0200 Subject: [PATCH 06/34] Use username as display name for suspended users or users with blank display names (#25276) --- app/serializers/activitypub/actor_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index e6dd8040e9..36397857f0 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -99,7 +99,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def name - object.suspended? ? '' : object.display_name + object.suspended? ? object.username : (object.display_name.presence || object.username) end def summary From e5f1000ad1c2817a62617f78ed21983bd4b38487 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 13:34:15 +0200 Subject: [PATCH 07/34] Fix CSP headers being unintendedly wide (#26105) --- .../initializers/content_security_policy.rb | 2 +- spec/requests/content_security_policy_spec.rb | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 spec/requests/content_security_policy_spec.rb diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 4cc9c204db..98c4f541f3 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -5,7 +5,7 @@ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy def host_to_url(str) - "http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}".split('/').first if str.present? + "http#{Rails.configuration.x.use_https ? 's' : ''}://#{str.split('/').first}" if str.present? end base_host = Rails.configuration.x.web_domain diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb new file mode 100644 index 0000000000..7eb27d61d6 --- /dev/null +++ b/spec/requests/content_security_policy_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Content-Security-Policy' do + it 'sets the expected CSP headers' do + allow(SecureRandom).to receive(:base64).with(16).and_return('ZbA+JmE7+bK8F5qvADZHuQ==') + + get '/' + expect(response.headers['Content-Security-Policy'].split(';').map(&:strip)).to contain_exactly( + "base-uri 'none'", + "default-src 'none'", + "frame-ancestors 'none'", + "font-src 'self' https://cb6e6126.ngrok.io", + "img-src 'self' https: data: blob: https://cb6e6126.ngrok.io", + "style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='", + "media-src 'self' https: data: https://cb6e6126.ngrok.io", + "frame-src 'self' https:", + "manifest-src 'self' https://cb6e6126.ngrok.io", + "form-action 'self'", + "child-src 'self' blob: https://cb6e6126.ngrok.io", + "worker-src 'self' blob: https://cb6e6126.ngrok.io", + "connect-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io ws://localhost:4000", + "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" + ) + end +end From 5b457961fc1189a71599dc6c06b3f159b195a455 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 14:21:10 +0200 Subject: [PATCH 08/34] Fix linting issue (#26106) --- spec/lib/vacuum/applications_vacuum_spec.rb | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/spec/lib/vacuum/applications_vacuum_spec.rb b/spec/lib/vacuum/applications_vacuum_spec.rb index d30311ab13..57a222aafc 100644 --- a/spec/lib/vacuum/applications_vacuum_spec.rb +++ b/spec/lib/vacuum/applications_vacuum_spec.rb @@ -6,43 +6,43 @@ RSpec.describe Vacuum::ApplicationsVacuum do subject { described_class.new } describe '#perform' do - let!(:app1) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app2) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app3) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app4) { Fabricate(:application, created_at: 1.month.ago, owner: Fabricate(:user)) } - let!(:app5) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app6) { Fabricate(:application, created_at: 1.hour.ago) } + let!(:app_with_token) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app_with_grant) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app_with_signup) { Fabricate(:application, created_at: 1.month.ago) } + let!(:app_with_owner) { Fabricate(:application, created_at: 1.month.ago, owner: Fabricate(:user)) } + let!(:unused_app) { Fabricate(:application, created_at: 1.month.ago) } + let!(:recent_app) { Fabricate(:application, created_at: 1.hour.ago) } - let!(:active_access_token) { Fabricate(:access_token, application: app1) } - let!(:active_access_grant) { Fabricate(:access_grant, application: app2) } - let!(:user) { Fabricate(:user, created_by_application: app3) } + let!(:active_access_token) { Fabricate(:access_token, application: app_with_token) } + let!(:active_access_grant) { Fabricate(:access_grant, application: app_with_grant) } + let!(:user) { Fabricate(:user, created_by_application: app_with_signup) } before do subject.perform end it 'does not delete applications with valid access tokens' do - expect { app1.reload }.to_not raise_error + expect { app_with_token.reload }.to_not raise_error end it 'does not delete applications with valid access grants' do - expect { app2.reload }.to_not raise_error + expect { app_with_grant.reload }.to_not raise_error end it 'does not delete applications that were used to create users' do - expect { app3.reload }.to_not raise_error + expect { app_with_signup.reload }.to_not raise_error end it 'does not delete owned applications' do - expect { app4.reload }.to_not raise_error + expect { app_with_owner.reload }.to_not raise_error end it 'does not delete applications registered less than a day ago' do - expect { app6.reload }.to_not raise_error + expect { recent_app.reload }.to_not raise_error end it 'deletes unused applications' do - expect { app5.reload }.to raise_error ActiveRecord::RecordNotFound + expect { unused_app.reload }.to raise_error ActiveRecord::RecordNotFound end end end From 217ef7f2aff08575c505368199f059c3c9d79df5 Mon Sep 17 00:00:00 2001 From: gunchleoc Date: Fri, 21 Jul 2023 19:09:13 +0200 Subject: [PATCH 09/34] Replace 'favourite' by 'favorite' for American English (#26009) --- .../mastodon/components/status_action_bar.jsx | 2 +- .../mastodon/containers/status_container.jsx | 2 +- .../features/account/components/header.jsx | 2 +- .../compose/components/action_bar.jsx | 2 +- .../mastodon/features/explore/statuses.jsx | 2 +- .../features/favourited_statuses/index.jsx | 4 +-- .../mastodon/features/favourites/index.jsx | 2 +- .../features/getting_started/index.jsx | 2 +- .../features/interaction_modal/index.jsx | 6 ++-- .../features/keyboard_shortcuts/index.jsx | 4 +-- .../components/column_settings.jsx | 2 +- .../notifications/components/filter_bar.jsx | 2 +- .../notifications/components/notification.jsx | 4 +-- .../picture_in_picture/components/footer.jsx | 2 +- .../features/status/components/action_bar.jsx | 2 +- .../containers/detailed_status_container.js | 2 +- .../mastodon/features/status/index.jsx | 2 +- .../ui/components/navigation_panel.jsx | 2 +- .../features/ui/components/sign_in_banner.jsx | 2 +- app/javascript/mastodon/locales/en.json | 32 +++++++++---------- config/locales/doorkeeper.en.yml | 6 ++-- 21 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index b713c98c68..5d441c10c2 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -31,7 +31,7 @@ const messages = defineMessages({ reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' }, cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, - favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, + favourite: { id: 'status.favourite', defaultMessage: 'Favorite' }, bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' }, removeBookmark: { id: 'status.remove_bookmark', defaultMessage: 'Remove bookmark' }, open: { id: 'status.open', defaultMessage: 'Expand this status' }, diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index 8b3d8b46b7..536765e137 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -54,7 +54,7 @@ const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' }, - redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' }, + redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, editConfirm: { id: 'confirmations.edit.confirm', defaultMessage: 'Edit' }, diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index ececb86c08..aea7317577 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -48,7 +48,7 @@ const messages = defineMessages({ pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, - favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, + favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' }, blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, diff --git a/app/javascript/mastodon/features/compose/components/action_bar.jsx b/app/javascript/mastodon/features/compose/components/action_bar.jsx index ac84014e48..7d119215e6 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.jsx +++ b/app/javascript/mastodon/features/compose/components/action_bar.jsx @@ -12,7 +12,7 @@ const messages = defineMessages({ pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, - favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, + favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' }, blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, diff --git a/app/javascript/mastodon/features/explore/statuses.jsx b/app/javascript/mastodon/features/explore/statuses.jsx index 043492fb89..f32a4a5368 100644 --- a/app/javascript/mastodon/features/explore/statuses.jsx +++ b/app/javascript/mastodon/features/explore/statuses.jsx @@ -47,7 +47,7 @@ class Statuses extends PureComponent { return ( <> - + ({ @@ -74,7 +74,7 @@ class Favourites extends ImmutablePureComponent { const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const pinned = !!columnId; - const emptyMessage = ; + const emptyMessage = ; return ( diff --git a/app/javascript/mastodon/features/favourites/index.jsx b/app/javascript/mastodon/features/favourites/index.jsx index 57911c3a14..bfde78708e 100644 --- a/app/javascript/mastodon/features/favourites/index.jsx +++ b/app/javascript/mastodon/features/favourites/index.jsx @@ -61,7 +61,7 @@ class Favourites extends ImmutablePureComponent { ); } - const emptyMessage = ; + const emptyMessage = ; return ( diff --git a/app/javascript/mastodon/features/getting_started/index.jsx b/app/javascript/mastodon/features/getting_started/index.jsx index 85fd6f1209..f0cd70d7a1 100644 --- a/app/javascript/mastodon/features/getting_started/index.jsx +++ b/app/javascript/mastodon/features/getting_started/index.jsx @@ -32,7 +32,7 @@ const messages = defineMessages({ bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, - favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, + favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' }, blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Blocked domains' }, mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, diff --git a/app/javascript/mastodon/features/interaction_modal/index.jsx b/app/javascript/mastodon/features/interaction_modal/index.jsx index 0f17a0896a..4722c130e7 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.jsx +++ b/app/javascript/mastodon/features/interaction_modal/index.jsx @@ -116,8 +116,8 @@ class InteractionModal extends PureComponent { break; case 'favourite': icon = ; - title = ; - actionDescription = ; + title = ; + actionDescription = ; break; case 'follow': icon = ; @@ -158,7 +158,7 @@ class InteractionModal extends PureComponent {

-

+

diff --git a/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx b/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx index ce4c6015b0..3dc21f7e8e 100644 --- a/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx +++ b/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx @@ -54,7 +54,7 @@ class KeyboardShortcuts extends ImmutablePureComponent { f - + b @@ -138,7 +138,7 @@ class KeyboardShortcuts extends ImmutablePureComponent { g+f - + g+p diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.jsx b/app/javascript/mastodon/features/notifications/components/column_settings.jsx index 7f8e88f080..09154f257a 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.jsx +++ b/app/javascript/mastodon/features/notifications/components/column_settings.jsx @@ -109,7 +109,7 @@ export default class ColumnSettings extends PureComponent {
- +
diff --git a/app/javascript/mastodon/features/notifications/components/filter_bar.jsx b/app/javascript/mastodon/features/notifications/components/filter_bar.jsx index 92cdfa57b6..773fe9a8f8 100644 --- a/app/javascript/mastodon/features/notifications/components/filter_bar.jsx +++ b/app/javascript/mastodon/features/notifications/components/filter_bar.jsx @@ -7,7 +7,7 @@ import { Icon } from 'mastodon/components/icon'; const tooltips = defineMessages({ mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' }, - favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favourites' }, + favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favorites' }, boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' }, polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' }, follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' }, diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx index 044e6969e6..43c5e85cef 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification.jsx @@ -20,7 +20,7 @@ import FollowRequestContainer from '../containers/follow_request_container'; import Report from './report'; const messages = defineMessages({ - favourite: { id: 'notification.favourite', defaultMessage: '{name} favourited your status' }, + favourite: { id: 'notification.favourite', defaultMessage: '{name} favorited your status' }, follow: { id: 'notification.follow', defaultMessage: '{name} followed you' }, ownPoll: { id: 'notification.own_poll', defaultMessage: 'Your poll has ended' }, poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' }, @@ -198,7 +198,7 @@ class Notification extends ImmutablePureComponent {
- +
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index c167d93dce..a368962b93 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -23,7 +23,7 @@ const messages = defineMessages({ reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' }, cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, - favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, + favourite: { id: 'status.favourite', defaultMessage: 'Favorite' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, open: { id: 'status.open', defaultMessage: 'Expand this status' }, diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index 0bacf29654..198afd29df 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -25,7 +25,7 @@ const messages = defineMessages({ reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' }, cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, - favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, + favourite: { id: 'status.favourite', defaultMessage: 'Favorite' }, bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' }, more: { id: 'status.more', defaultMessage: 'More' }, mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' }, diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js index 57d5f61c85..3e1f8d4d29 100644 --- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -36,7 +36,7 @@ const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' }, - redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' }, + redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, }); diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 4f58c7d2fd..1713d94eb5 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -72,7 +72,7 @@ const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' }, - redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' }, + redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' }, revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' }, hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' }, statusTitleWithAttachments: { id: 'status.title.with_attachments', defaultMessage: '{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}' }, diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index ab5c78246f..d36abf8f17 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -23,7 +23,7 @@ const messages = defineMessages({ explore: { id: 'explore.title', defaultMessage: 'Explore' }, firehose: { id: 'column.firehose', defaultMessage: 'Live feeds' }, direct: { id: 'navigation_bar.direct', defaultMessage: 'Private mentions' }, - favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, + favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' }, bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, diff --git a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx index abae34f7fd..e44b797692 100644 --- a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx +++ b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx @@ -35,7 +35,7 @@ const SignInBanner = () => { return (
-

+

{signupButton}
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 8c85cb7bea..c62f485534 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -113,7 +113,7 @@ "column.direct": "Private mentions", "column.directory": "Browse profiles", "column.domain_blocks": "Blocked domains", - "column.favourites": "Favourites", + "column.favourites": "Favorites", "column.firehose": "Live feeds", "column.follow_requests": "Follow requests", "column.home": "Home", @@ -181,7 +181,7 @@ "confirmations.mute.explanation": "This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.", "confirmations.mute.message": "Are you sure you want to mute {name}?", "confirmations.redraft.confirm": "Delete & redraft", - "confirmations.redraft.message": "Are you sure you want to delete this post and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.", + "confirmations.redraft.message": "Are you sure you want to delete this post and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.", "confirmations.reply.confirm": "Reply", "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", "confirmations.unfollow.confirm": "Unfollow", @@ -202,7 +202,7 @@ "dismissable_banner.community_timeline": "These are the most recent public posts from people whose accounts are hosted by {domain}.", "dismissable_banner.dismiss": "Dismiss", "dismissable_banner.explore_links": "These are news stories being shared the most on the social web today. Newer news stories posted by more different people are ranked higher.", - "dismissable_banner.explore_statuses": "These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favourites are ranked higher.", + "dismissable_banner.explore_statuses": "These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favorites are ranked higher.", "dismissable_banner.explore_tags": "These are hashtags that are gaining traction on the social web today. Hashtags that are used by more different people are ranked higher.", "dismissable_banner.public_timeline": "These are the most recent public posts from people on the social web that people on {domain} follow.", "embed.instructions": "Embed this post on your website by copying the code below.", @@ -231,8 +231,8 @@ "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.", "empty_column.domain_blocks": "There are no blocked domains yet.", "empty_column.explore_statuses": "Nothing is trending right now. Check back later!", - "empty_column.favourited_statuses": "You don't have any favourite posts yet. When you favourite one, it will show up here.", - "empty_column.favourites": "No one has favourited this post yet. When someone does, they will show up here.", + "empty_column.favourited_statuses": "You don't have any favorite posts yet. When you favorite one, it will show up here.", + "empty_column.favourites": "No one has favorited this post yet. When someone does, they will show up here.", "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", "empty_column.followed_tags": "You have not followed any hashtags yet. When you do, they will show up here.", "empty_column.hashtag": "There is nothing in this hashtag yet.", @@ -307,15 +307,15 @@ "home.explore_prompt.title": "This is your home base within Mastodon.", "home.hide_announcements": "Hide announcements", "home.show_announcements": "Show announcements", - "interaction_modal.description.favourite": "With an account on Mastodon, you can favourite this post to let the author know you appreciate it and save it for later.", + "interaction_modal.description.favourite": "With an account on Mastodon, you can favorite this post to let the author know you appreciate it and save it for later.", "interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.", "interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.", "interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.", "interaction_modal.on_another_server": "On a different server", "interaction_modal.on_this_server": "On this server", - "interaction_modal.other_server_instructions": "Copy and paste this URL into the search field of your favourite Mastodon app or the web interface of your Mastodon server.", + "interaction_modal.other_server_instructions": "Copy and paste this URL into the search field of your favorite Mastodon app or the web interface of your Mastodon server.", "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.", - "interaction_modal.title.favourite": "Favourite {name}'s post", + "interaction_modal.title.favourite": "Favorite {name}'s post", "interaction_modal.title.follow": "Follow {name}", "interaction_modal.title.reblog": "Boost {name}'s post", "interaction_modal.title.reply": "Reply to {name}'s post", @@ -331,8 +331,8 @@ "keyboard_shortcuts.direct": "to open private mentions column", "keyboard_shortcuts.down": "Move down in the list", "keyboard_shortcuts.enter": "Open post", - "keyboard_shortcuts.favourite": "Favourite post", - "keyboard_shortcuts.favourites": "Open favourites list", + "keyboard_shortcuts.favourite": "Favorite post", + "keyboard_shortcuts.favourites": "Open favorites list", "keyboard_shortcuts.federated": "Open federated timeline", "keyboard_shortcuts.heading": "Keyboard shortcuts", "keyboard_shortcuts.home": "Open home timeline", @@ -395,7 +395,7 @@ "navigation_bar.domain_blocks": "Blocked domains", "navigation_bar.edit_profile": "Edit profile", "navigation_bar.explore": "Explore", - "navigation_bar.favourites": "Favourites", + "navigation_bar.favourites": "Favorites", "navigation_bar.filters": "Muted words", "navigation_bar.follow_requests": "Follow requests", "navigation_bar.followed_tags": "Followed hashtags", @@ -412,7 +412,7 @@ "not_signed_in_indicator.not_signed_in": "You need to login to access this resource.", "notification.admin.report": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", - "notification.favourite": "{name} favourited your post", + "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", "notification.mention": "{name} mentioned you", @@ -426,7 +426,7 @@ "notifications.column_settings.admin.report": "New reports:", "notifications.column_settings.admin.sign_up": "New sign-ups:", "notifications.column_settings.alert": "Desktop notifications", - "notifications.column_settings.favourite": "Favourites:", + "notifications.column_settings.favourite": "Favorites:", "notifications.column_settings.filter_bar.advanced": "Display all categories", "notifications.column_settings.filter_bar.category": "Quick filter bar", "notifications.column_settings.filter_bar.show_bar": "Show filter bar", @@ -444,7 +444,7 @@ "notifications.column_settings.update": "Edits:", "notifications.filter.all": "All", "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourites", + "notifications.filter.favourites": "Favourits", "notifications.filter.follows": "Follows", "notifications.filter.mentions": "Mentions", "notifications.filter.polls": "Poll results", @@ -595,7 +595,7 @@ "server_banner.server_stats": "Server stats:", "sign_in_banner.create_account": "Create account", "sign_in_banner.sign_in": "Login", - "sign_in_banner.text": "Login to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.", + "sign_in_banner.text": "Login to follow profiles or hashtags, favorite, share and reply to posts. You can also interact from your account on a different server.", "status.admin_account": "Open moderation interface for @{name}", "status.admin_domain": "Open moderation interface for {domain}", "status.admin_status": "Open this post in the moderation interface", @@ -612,7 +612,7 @@ "status.edited": "Edited {date}", "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}", "status.embed": "Embed", - "status.favourite": "Favourite", + "status.favourite": "Favorite", "status.filter": "Filter this post", "status.filtered": "Filtered", "status.hide": "Hide post", diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index a28f91c0e0..0432a5e3fb 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -127,7 +127,7 @@ en: bookmarks: Bookmarks conversations: Conversations crypto: End-to-end encryption - favourites: Favourites + favourites: Favorites filters: Filters follow: Follows, Mutes and Blocks follows: Follows @@ -170,7 +170,7 @@ en: read:accounts: see accounts information read:blocks: see your blocks read:bookmarks: see your bookmarks - read:favourites: see your favourites + read:favourites: see your favorites read:filters: see your filters read:follows: see your follows read:lists: see your lists @@ -184,7 +184,7 @@ en: write:blocks: block accounts and domains write:bookmarks: bookmark posts write:conversations: mute and delete conversations - write:favourites: favourite posts + write:favourites: favorite posts write:filters: create filters write:follows: follow people write:lists: create lists From 296ec6cf57bb4f5cbf152c0083f38b1c96930391 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Fri, 21 Jul 2023 21:12:57 +0200 Subject: [PATCH 10/34] Override default Action Mailer `preview_path` (#26110) --- config/application.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/application.rb b/config/application.rb index aa0f80cd08..6f21efa8db 100644 --- a/config/application.rb +++ b/config/application.rb @@ -192,7 +192,9 @@ module Mastodon # config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')] config.active_job.queue_adapter = :sidekiq + config.action_mailer.deliver_later_queue_name = 'mailers' + config.action_mailer.preview_path = Rails.root.join('spec', 'mailers', 'previews') # We use our own middleware for this config.public_file_server.enabled = false From 1b4cf0eba0699fa6b033139d4fce9891519c2f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Fri, 21 Jul 2023 21:13:20 +0200 Subject: [PATCH 11/34] Favourits -> Favorites (#26109) --- app/javascript/mastodon/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index c62f485534..cf4e802eb4 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -444,7 +444,7 @@ "notifications.column_settings.update": "Edits:", "notifications.filter.all": "All", "notifications.filter.boosts": "Boosts", - "notifications.filter.favourites": "Favourits", + "notifications.filter.favourites": "Favorites", "notifications.filter.follows": "Follows", "notifications.filter.mentions": "Mentions", "notifications.filter.polls": "Poll results", From f2c683336bb27bc457b779e5e0c35cc21b2b45af Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 21 Jul 2023 21:23:14 +0200 Subject: [PATCH 12/34] Bump version to v4.1.5 (#26108) --- CHANGELOG.md | 20 ++++++++++++++++++++ docker-compose.yml | 6 +++--- lib/mastodon/version.rb | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5383d426b6..c49b192735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ All notable changes to this project will be documented in this file. +## [4.1.5] - 2023-07-21 + +### Added + +- Add check preventing Sidekiq workers from running with Makara configured ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25850)) + +### Changed + +- Change request timeout handling to use a longer deadline ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26055)) + +### Fixed + +- Fix moderation interface for remote instances with a .zip TLD ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25885)) +- Fix remote accounts being possibly persisted to database with incomplete protocol values ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25886)) +- Fix trending publishers table not rendering correctly on narrow screens ([vmstan](https://github.com/mastodon/mastodon/pull/25945)) + +### Security + +- Fix CSP headers being unintentionally wide ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26105)) + ## [4.1.4] - 2023-07-07 ### Fixed diff --git a/docker-compose.yml b/docker-compose.yml index f603c2f7e2..e3fa9ae1e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -56,7 +56,7 @@ services: web: build: . - image: ghcr.io/mastodon/mastodon + image: ghcr.io/mastodon/mastodon:v4.1.5 restart: always env_file: .env.production command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" @@ -77,7 +77,7 @@ services: streaming: build: . - image: ghcr.io/mastodon/mastodon + image: ghcr.io/mastodon/mastodon:v4.1.5 restart: always env_file: .env.production command: node ./streaming @@ -95,7 +95,7 @@ services: sidekiq: build: . - image: ghcr.io/mastodon/mastodon + image: ghcr.io/mastodon/mastodon:v4.1.5 restart: always env_file: .env.production command: bundle exec sidekiq diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index cbec893e02..17af0c051a 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 4 + 5 end def flags From 0078e7e760a94d30ff02e0fc6db11b01311b8b90 Mon Sep 17 00:00:00 2001 From: Claire Date: Sat, 22 Jul 2023 20:42:31 +0200 Subject: [PATCH 13/34] Fix incorrect connect timeout in outgoing requests (#26116) --- app/lib/request.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/request.rb b/app/lib/request.rb index 7386015d6d..c7aafbd4fc 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -284,11 +284,11 @@ class Request end until socks.empty? - _, available_socks, = IO.select(nil, socks, nil, Request::TIMEOUT[:connect]) + _, available_socks, = IO.select(nil, socks, nil, Request::TIMEOUT[:connect_timeout]) if available_socks.nil? socks.each(&:close) - raise HTTP::TimeoutError, "Connect timed out after #{Request::TIMEOUT[:connect]} seconds" + raise HTTP::TimeoutError, "Connect timed out after #{Request::TIMEOUT[:connect_timeout]} seconds" end available_socks.each do |sock| From db310f383d5730f3245f5f9f361ad09d63b0a3ef Mon Sep 17 00:00:00 2001 From: mogaminsk Date: Sun, 23 Jul 2023 22:57:57 +0900 Subject: [PATCH 14/34] Fix missing translation strings for importing lists (#26120) --- config/i18n-tasks.yml | 4 ++-- config/locales/en.yml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index b3bb336ed2..d0677b80fb 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -65,8 +65,8 @@ ignore_unused: - 'move_handler.carry_{mutes,blocks}_over_text' - 'admin_mailer.*.subject' - 'notification_mailer.*' - - 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks}_html' - - 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks}_html' + - 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html' + - 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html' - 'mail_subscriptions.unsubscribe.emails.*' - 'preferences.other' # some locales are missing other keys, therefore leading i18n-tasks to detect `preferences` as plural and not finding use diff --git a/config/locales/en.yml b/config/locales/en.yml index 9e54c2d8dd..d31da27284 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1278,12 +1278,14 @@ en: bookmarks_html: You are about to replace your bookmarks with up to %{total_items} posts from %{filename}. domain_blocking_html: You are about to replace your domain block list with up to %{total_items} domains from %{filename}. following_html: You are about to follow up to %{total_items} accounts from %{filename} and stop following anyone else. + lists_html: You are about to replace your lists with contents of %{filename}. Up to %{total_items} accounts will be added to new lists. muting_html: You are about to replace your list of muted accounts with up to %{total_items} accounts from %{filename}. preambles: blocking_html: You are about to block up to %{total_items} accounts from %{filename}. bookmarks_html: You are about to add up to %{total_items} posts from %{filename} to your bookmarks. domain_blocking_html: You are about to block up to %{total_items} domains from %{filename}. following_html: You are about to follow up to %{total_items} accounts from %{filename}. + lists_html: You are about to add up to %{total_items} accounts from %{filename} to your lists. New lists will be created if there is no list to add to. muting_html: You are about to mute up to %{total_items} accounts from %{filename}. preface: You can import data that you have exported from another server, such as a list of the people you are following or blocking. recent_imports: Recent imports @@ -1300,6 +1302,7 @@ en: bookmarks: Importing bookmarks domain_blocking: Importing blocked domains following: Importing followed accounts + lists: Importing lists muting: Importing muted accounts type: Import type type_groups: @@ -1310,6 +1313,7 @@ en: bookmarks: Bookmarks domain_blocking: Domain blocking list following: Following list + lists: Lists muting: Muting list upload: Upload invites: From 3abe0fc5c850bf6ac625e168b33d92641a534700 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Sun, 23 Jul 2023 15:58:19 +0200 Subject: [PATCH 15/34] Use valid email address for first account (#26114) --- db/seeds/04_admin.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/db/seeds/04_admin.rb b/db/seeds/04_admin.rb index ec0287a454..c9b0369c9f 100644 --- a/db/seeds/04_admin.rb +++ b/db/seeds/04_admin.rb @@ -2,6 +2,7 @@ if Rails.env.development? domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain + domain = domain.gsub(/:\d+$/, '') admin = Account.where(username: 'admin').first_or_initialize(username: 'admin') admin.save(validate: false) From 67016dd29db51e640544806e972d0031829a09e3 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Sun, 23 Jul 2023 11:48:16 -0400 Subject: [PATCH 16/34] Update haml-lint 0.49.1 (#26118) --- Gemfile.lock | 2 +- app/views/admin/announcements/index.html.haml | 1 - app/views/admin/custom_emojis/index.html.haml | 1 - app/views/admin/ip_blocks/index.html.haml | 1 - app/views/admin/relays/index.html.haml | 1 - app/views/admin/roles/edit.html.haml | 1 - app/views/settings/applications/show.html.haml | 1 - 7 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 63a9388ee2..bc4f3522bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -307,7 +307,7 @@ GEM activesupport (>= 5.1) haml (>= 4.0.6) railties (>= 5.1) - haml_lint (0.48.0) + haml_lint (0.49.1) haml (>= 4.0, < 6.2) parallel (~> 1.10) rainbow diff --git a/app/views/admin/announcements/index.html.haml b/app/views/admin/announcements/index.html.haml index ce520f59d3..72227b0457 100644 --- a/app/views/admin/announcements/index.html.haml +++ b/app/views/admin/announcements/index.html.haml @@ -19,4 +19,3 @@ = render partial: 'announcement', collection: @announcements = paginate @announcements - diff --git a/app/views/admin/custom_emojis/index.html.haml b/app/views/admin/custom_emojis/index.html.haml index 6ded4b4332..eb41563ee6 100644 --- a/app/views/admin/custom_emojis/index.html.haml +++ b/app/views/admin/custom_emojis/index.html.haml @@ -85,4 +85,3 @@ = render partial: 'custom_emoji', collection: @custom_emojis, locals: { f: f } = paginate @custom_emojis - diff --git a/app/views/admin/ip_blocks/index.html.haml b/app/views/admin/ip_blocks/index.html.haml index d5b983de9e..675c0aaad0 100644 --- a/app/views/admin/ip_blocks/index.html.haml +++ b/app/views/admin/ip_blocks/index.html.haml @@ -25,4 +25,3 @@ = render partial: 'ip_block', collection: @ip_blocks, locals: { f: f } = paginate @ip_blocks - diff --git a/app/views/admin/relays/index.html.haml b/app/views/admin/relays/index.html.haml index 1636a53f85..47f8d6f360 100644 --- a/app/views/admin/relays/index.html.haml +++ b/app/views/admin/relays/index.html.haml @@ -17,4 +17,3 @@ %th %tbody = render @relays - diff --git a/app/views/admin/roles/edit.html.haml b/app/views/admin/roles/edit.html.haml index 659ccb8dce..5688b69b1f 100644 --- a/app/views/admin/roles/edit.html.haml +++ b/app/views/admin/roles/edit.html.haml @@ -5,4 +5,3 @@ = link_to t('admin.roles.delete'), admin_role_path(@role), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:destroy, @role) = render partial: 'form' - diff --git a/app/views/settings/applications/show.html.haml b/app/views/settings/applications/show.html.haml index 466a8ba340..be1d13eae6 100644 --- a/app/views/settings/applications/show.html.haml +++ b/app/views/settings/applications/show.html.haml @@ -28,4 +28,3 @@ .actions = f.button :button, t('generic.save_changes'), type: :submit - From cfd50f30bb5dda4dd90e1ad01f3e62c99135c36f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 23 Jul 2023 17:55:13 +0200 Subject: [PATCH 17/34] Fix focus and hover styles in web UI (#26125) --- .../intersection_observer_article.jsx | 4 +- .../styles/mastodon/components.scss | 74 ++++++++++--------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/app/javascript/mastodon/components/intersection_observer_article.jsx b/app/javascript/mastodon/components/intersection_observer_article.jsx index 7b03ffb88e..8efa969f9b 100644 --- a/app/javascript/mastodon/components/intersection_observer_article.jsx +++ b/app/javascript/mastodon/components/intersection_observer_article.jsx @@ -114,7 +114,7 @@ export default class IntersectionObserverArticle extends Component { aria-setsize={listLength} style={{ height: `${this.height || cachedHeight}px`, opacity: 0, overflow: 'hidden' }} data-id={id} - tabIndex={0} + tabIndex={-1} > {children && cloneElement(children, { hidden: true })} @@ -122,7 +122,7 @@ export default class IntersectionObserverArticle extends Component { } return ( -
+
{children && cloneElement(children, { hidden: false })}
); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index d08cb28038..bb0febaaef 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -74,7 +74,7 @@ background-color: $ui-button-focus-background-color; } - &:focus { + &:focus-visible { outline: $ui-button-icon-focus-outline; } @@ -191,8 +191,6 @@ border-radius: 4px; background: transparent; cursor: pointer; - transition: all 100ms ease-out; - transition-property: background-color, color; text-decoration: none; a { @@ -203,11 +201,11 @@ &:hover, &:active, &:focus { - color: lighten($action-button-color, 20%); - background-color: $ui-button-icon-hover-background-color; + color: lighten($action-button-color, 7%); + background-color: rgba($action-button-color, 0.15); } - &:focus { + &:focus-visible { outline: $ui-button-icon-focus-outline; } @@ -224,10 +222,10 @@ &:active, &:focus { color: darken($lighter-text-color, 7%); - background-color: $ui-button-icon-hover-background-color; + background-color: rgba($lighter-text-color, 0.15); } - &:focus { + &:focus-visible { outline: $ui-button-icon-focus-outline; } @@ -239,6 +237,13 @@ &.active { color: $highlight-text-color; + &:hover, + &:active, + &:focus { + color: $highlight-text-color; + background-color: transparent; + } + &.disabled { color: lighten($highlight-text-color, 13%); } @@ -283,19 +288,15 @@ font-size: 11px; padding: 0 3px; line-height: 27px; - transition: all 100ms ease-in; - transition-property: background-color, color; &:hover, &:active, &:focus { color: darken($lighter-text-color, 7%); - background-color: $ui-button-icon-hover-background-color; - transition: all 200ms ease-out; - transition-property: background-color, color; + background-color: rgba($lighter-text-color, 0.15); } - &:focus { + &:focus-visible { outline: $ui-button-icon-focus-outline; } @@ -307,6 +308,13 @@ &.active { color: $highlight-text-color; + + &:hover, + &:active, + &:focus { + color: $highlight-text-color; + background-color: transparent; + } } } @@ -1975,7 +1983,7 @@ a.account__display-name { font-size: inherit; line-height: inherit; - &:focus { + &:focus-visible { outline: 1px dotted; } } @@ -3838,7 +3846,6 @@ a.status-card.compact:hover { position: relative; z-index: 2; outline: 0; - overflow: hidden; & > button { margin: 0; @@ -3853,6 +3860,10 @@ a.status-card.compact:hover { overflow: hidden; white-space: nowrap; flex: 1; + + &:focus-visible { + outline: $ui-button-icon-focus-outline; + } } & > .column-header__back-button { @@ -3893,10 +3904,18 @@ a.status-card.compact:hover { font-size: 16px; padding: 0 15px; + &:last-child { + border-start-end-radius: 4px; + } + &:hover { color: lighten($darker-text-color, 4%); } + &:focus-visible { + outline: $ui-button-icon-focus-outline; + } + &.active { color: $primary-text-color; background: lighten($ui-base-color, 4%); @@ -4542,7 +4561,7 @@ a.status-card.compact:hover { .emoji-picker-dropdown__menu { background: $simple-background-color; position: relative; - box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4); + box-shadow: var(--dropdown-shadow); border-radius: 4px; margin-top: 5px; z-index: 2; @@ -4720,7 +4739,7 @@ a.status-card.compact:hover { } } - &:focus { + &:focus-visible { img { outline: $ui-button-icon-focus-outline; } @@ -4734,7 +4753,7 @@ a.status-card.compact:hover { .privacy-dropdown__dropdown { background: $simple-background-color; - box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); + box-shadow: var(--dropdown-shadow); border-radius: 4px; overflow: hidden; z-index: 2; @@ -4811,19 +4830,6 @@ a.status-card.compact:hover { .privacy-dropdown__value { background: $simple-background-color; border-radius: 4px 4px 0 0; - box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1); - - .icon-button { - transition: none; - } - - &.active { - background: $ui-highlight-color; - - .icon-button { - color: $primary-text-color; - } - } } &.top .privacy-dropdown__value { @@ -4832,14 +4838,14 @@ a.status-card.compact:hover { .privacy-dropdown__dropdown { display: block; - box-shadow: 2px 4px 6px rgba($base-shadow-color, 0.1); + box-shadow: var(--dropdown-shadow); } } .language-dropdown { &__dropdown { background: $simple-background-color; - box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); + box-shadow: var(--dropdown-shadow); border-radius: 4px; overflow: hidden; z-index: 2; From 5e8cbb5f82ab0df0de80539650a6e55d7cf7a3a5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 23 Jul 2023 17:55:20 +0200 Subject: [PATCH 18/34] Remove back button from bookmarks, favourites and lists screens in web UI (#26126) --- app/javascript/mastodon/features/bookmarked_statuses/index.jsx | 1 - app/javascript/mastodon/features/favourited_statuses/index.jsx | 1 - app/javascript/mastodon/features/lists/index.jsx | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx index 936dee12e3..b0c90a4302 100644 --- a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx +++ b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx @@ -86,7 +86,6 @@ class Bookmarks extends ImmutablePureComponent { onClick={this.handleHeaderClick} pinned={pinned} multiColumn={multiColumn} - showBackButton /> - + From 4d01d1a1eeef7a851b77def9c5bfc2ce4d7a271c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 24 Jul 2023 13:46:55 +0200 Subject: [PATCH 19/34] Remove 16:9 cropping from web UI (#26132) --- .../mastodon/components/media_gallery.jsx | 15 +- .../picture_in_picture_placeholder.jsx | 5 +- app/javascript/mastodon/components/status.jsx | 50 +++-- .../status/components/detailed_status.jsx | 28 ++- .../features/ui/components/media_modal.jsx | 1 + .../features/ui/components/video_modal.jsx | 1 + .../mastodon/features/video/index.jsx | 172 +++++++++--------- app/javascript/mastodon/initial_state.js | 2 - .../styles/mastodon/components.scss | 23 +-- app/models/concerns/has_user_settings.rb | 4 - app/models/user_settings.rb | 1 - app/serializers/initial_state_serializer.rb | 2 - .../preferences/appearance/show.html.haml | 5 - config/locales/an.yml | 1 - config/locales/ar.yml | 1 - config/locales/ast.yml | 1 - config/locales/be.yml | 1 - config/locales/bg.yml | 1 - config/locales/ca.yml | 1 - config/locales/ckb.yml | 1 - config/locales/co.yml | 1 - config/locales/cs.yml | 1 - config/locales/cy.yml | 1 - config/locales/da.yml | 1 - config/locales/de.yml | 1 - config/locales/el.yml | 1 - config/locales/en-GB.yml | 1 - config/locales/en.yml | 1 - config/locales/eo.yml | 1 - config/locales/es-AR.yml | 1 - config/locales/es-MX.yml | 1 - config/locales/es.yml | 1 - config/locales/et.yml | 1 - config/locales/eu.yml | 1 - config/locales/fa.yml | 1 - config/locales/fi.yml | 1 - config/locales/fo.yml | 1 - config/locales/fr-QC.yml | 1 - config/locales/fr.yml | 1 - config/locales/fy.yml | 1 - config/locales/gd.yml | 1 - config/locales/gl.yml | 1 - config/locales/he.yml | 1 - config/locales/hu.yml | 1 - config/locales/id.yml | 1 - config/locales/io.yml | 1 - config/locales/is.yml | 1 - config/locales/it.yml | 1 - config/locales/ja.yml | 1 - config/locales/kk.yml | 1 - config/locales/ko.yml | 1 - config/locales/ku.yml | 1 - config/locales/lv.yml | 1 - config/locales/my.yml | 1 - config/locales/nl.yml | 1 - config/locales/nn.yml | 1 - config/locales/no.yml | 1 - config/locales/oc.yml | 1 - config/locales/pl.yml | 1 - config/locales/pt-BR.yml | 1 - config/locales/pt-PT.yml | 1 - config/locales/ro.yml | 1 - config/locales/ru.yml | 1 - config/locales/sc.yml | 1 - config/locales/sco.yml | 1 - config/locales/si.yml | 1 - config/locales/simple_form.an.yml | 1 - config/locales/simple_form.ar.yml | 1 - config/locales/simple_form.ast.yml | 1 - config/locales/simple_form.be.yml | 1 - config/locales/simple_form.bg.yml | 1 - config/locales/simple_form.ca.yml | 1 - config/locales/simple_form.ckb.yml | 1 - config/locales/simple_form.co.yml | 1 - config/locales/simple_form.cs.yml | 1 - config/locales/simple_form.cy.yml | 1 - config/locales/simple_form.da.yml | 1 - config/locales/simple_form.de.yml | 1 - config/locales/simple_form.el.yml | 1 - config/locales/simple_form.en-GB.yml | 1 - config/locales/simple_form.en.yml | 1 - config/locales/simple_form.eo.yml | 1 - config/locales/simple_form.es-AR.yml | 1 - config/locales/simple_form.es-MX.yml | 1 - config/locales/simple_form.es.yml | 1 - config/locales/simple_form.et.yml | 1 - config/locales/simple_form.eu.yml | 1 - config/locales/simple_form.fa.yml | 1 - config/locales/simple_form.fi.yml | 1 - config/locales/simple_form.fo.yml | 1 - config/locales/simple_form.fr-QC.yml | 1 - config/locales/simple_form.fr.yml | 1 - config/locales/simple_form.fy.yml | 1 - config/locales/simple_form.gd.yml | 1 - config/locales/simple_form.gl.yml | 1 - config/locales/simple_form.he.yml | 1 - config/locales/simple_form.hu.yml | 1 - config/locales/simple_form.hy.yml | 1 - config/locales/simple_form.id.yml | 1 - config/locales/simple_form.io.yml | 1 - config/locales/simple_form.is.yml | 1 - config/locales/simple_form.it.yml | 1 - config/locales/simple_form.ja.yml | 1 - config/locales/simple_form.kk.yml | 1 - config/locales/simple_form.ko.yml | 1 - config/locales/simple_form.ku.yml | 1 - config/locales/simple_form.lv.yml | 1 - config/locales/simple_form.my.yml | 1 - config/locales/simple_form.nl.yml | 1 - config/locales/simple_form.nn.yml | 1 - config/locales/simple_form.no.yml | 1 - config/locales/simple_form.oc.yml | 1 - config/locales/simple_form.pl.yml | 1 - config/locales/simple_form.pt-BR.yml | 1 - config/locales/simple_form.pt-PT.yml | 1 - config/locales/simple_form.ro.yml | 1 - config/locales/simple_form.ru.yml | 1 - config/locales/simple_form.sc.yml | 1 - config/locales/simple_form.sco.yml | 1 - config/locales/simple_form.si.yml | 1 - config/locales/simple_form.sk.yml | 1 - config/locales/simple_form.sl.yml | 1 - config/locales/simple_form.sq.yml | 1 - config/locales/simple_form.sr-Latn.yml | 1 - config/locales/simple_form.sr.yml | 1 - config/locales/simple_form.sv.yml | 1 - config/locales/simple_form.th.yml | 1 - config/locales/simple_form.tr.yml | 1 - config/locales/simple_form.uk.yml | 1 - config/locales/simple_form.vi.yml | 1 - config/locales/simple_form.zh-CN.yml | 1 - config/locales/simple_form.zh-HK.yml | 1 - config/locales/simple_form.zh-TW.yml | 1 - config/locales/sk.yml | 1 - config/locales/sl.yml | 1 - config/locales/sq.yml | 1 - config/locales/sr-Latn.yml | 1 - config/locales/sr.yml | 1 - config/locales/sv.yml | 1 - config/locales/th.yml | 1 - config/locales/tr.yml | 1 - config/locales/uk.yml | 1 - config/locales/vi.yml | 1 - config/locales/zh-CN.yml | 1 - config/locales/zh-HK.yml | 1 - config/locales/zh-TW.yml | 1 - 146 files changed, 158 insertions(+), 284 deletions(-) diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index e3c0065c95..0b633a5b40 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -12,7 +12,7 @@ import { debounce } from 'lodash'; import { Blurhash } from 'mastodon/components/blurhash'; -import { autoPlayGif, cropImages, displayMedia, useBlurhash } from '../initial_state'; +import { autoPlayGif, displayMedia, useBlurhash } from '../initial_state'; import { IconButton } from './icon_button'; @@ -209,7 +209,6 @@ class MediaGallery extends PureComponent { static propTypes = { sensitive: PropTypes.bool, - standalone: PropTypes.bool, media: ImmutablePropTypes.list.isRequired, lang: PropTypes.string, size: PropTypes.object, @@ -223,10 +222,6 @@ class MediaGallery extends PureComponent { onToggleVisibility: PropTypes.func, }; - static defaultProps = { - standalone: false, - }; - state = { visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'), width: this.props.defaultWidth, @@ -295,7 +290,7 @@ class MediaGallery extends PureComponent { } render () { - const { media, lang, intl, sensitive, defaultWidth, standalone, autoplay } = this.props; + const { media, lang, intl, sensitive, defaultWidth, autoplay } = this.props; const { visible } = this.state; const width = this.state.width || defaultWidth; @@ -303,16 +298,16 @@ class MediaGallery extends PureComponent { const style = {}; - if (this.isFullSizeEligible() && (standalone || !cropImages)) { + if (this.isFullSizeEligible()) { style.aspectRatio = `${this.props.media.getIn([0, 'meta', 'small', 'aspect'])}`; } else { - style.aspectRatio = '16 / 9'; + style.aspectRatio = '3 / 2'; } const size = media.take(4).size; const uncached = media.every(attachment => attachment.get('type') === 'unknown'); - if (standalone && this.isFullSizeEligible()) { + if (this.isFullSizeEligible()) { children = ; } else { children = media.take(4).map((attachment, i) => ); diff --git a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx index 756a977224..c65bd494f3 100644 --- a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx +++ b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx @@ -12,6 +12,7 @@ class PictureInPicturePlaceholder extends PureComponent { static propTypes = { dispatch: PropTypes.func.isRequired, + aspectRatio: PropTypes.string, }; handleClick = () => { @@ -20,8 +21,10 @@ class PictureInPicturePlaceholder extends PureComponent { }; render () { + const { aspectRatio } = this.props; + return ( -
+
diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 8f188a638c..37951d5782 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -19,7 +19,6 @@ import Bundle from '../features/ui/components/bundle'; import { MediaGallery, Video, Audio } from '../features/ui/util/async-components'; import { displayMedia } from '../initial_state'; -import AttachmentList from './attachment_list'; import { Avatar } from './avatar'; import { AvatarOverlay } from './avatar_overlay'; import { DisplayName } from './display_name'; @@ -191,17 +190,35 @@ class Status extends ImmutablePureComponent { this.props.onTranslate(this._properStatus()); }; - renderLoadingMediaGallery () { - return
; + getAttachmentAspectRatio () { + const attachments = this._properStatus().get('media_attachments'); + + if (attachments.getIn([0, 'type']) === 'video') { + return `${attachments.getIn([0, 'meta', 'original', 'width'])} / ${attachments.getIn([0, 'meta', 'original', 'height'])}`; + } else if (attachments.getIn([0, 'type']) === 'audio') { + return '16 / 9'; + } else { + return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2' + } } - renderLoadingVideoPlayer () { - return
; - } + renderLoadingMediaGallery = () => { + return ( +
+ ); + }; - renderLoadingAudioPlayer () { - return
; - } + renderLoadingVideoPlayer = () => { + return ( +
+ ); + }; + + renderLoadingAudioPlayer = () => { + return ( +
+ ); + }; handleOpenVideo = (options) => { const status = this._properStatus(); @@ -426,18 +443,11 @@ class Status extends ImmutablePureComponent { } if (pictureInPicture.get('inUse')) { - media = ; + media = ; } else if (status.get('media_attachments').size > 0) { const language = status.getIn(['translation', 'language']) || status.get('language'); - if (this.props.muted) { - media = ( - - ); - } else if (status.getIn(['media_attachments', 0, 'type']) === 'audio') { + if (status.getIn(['media_attachments', 0, 'type']) === 'audio') { const attachment = status.getIn(['media_attachments', 0]); const description = attachment.getIn(['translation', 'description']) || attachment.get('description'); @@ -475,11 +485,11 @@ class Status extends ImmutablePureComponent { ); } - } else if (status.get('spoiler_text').length === 0 && status.get('card') && !this.props.muted) { + } else if (status.get('spoiler_text').length === 0 && status.get('card')) { media = ( ; + media = ; } else if (status.get('media_attachments').size > 0) { if (status.getIn(['media_attachments', 0, 'type']) === 'audio') { const attachment = status.getIn(['media_attachments', 0]); @@ -167,13 +189,13 @@ class DetailedStatus extends ImmutablePureComponent {