diff --git a/.devcontainer/compose.yaml b/.devcontainer/compose.yaml index 5da1ec3a24..ced5ecfe88 100644 --- a/.devcontainer/compose.yaml +++ b/.devcontainer/compose.yaml @@ -9,6 +9,7 @@ services: environment: RAILS_ENV: development NODE_ENV: development + VITE_RUBY_HOST: 0.0.0.0 BIND: 0.0.0.0 BOOTSNAP_CACHE_DIR: /tmp REDIS_HOST: redis @@ -22,11 +23,12 @@ services: ES_PORT: '9200' LIBRE_TRANSLATE_ENDPOINT: http://libretranslate:5000 LOCAL_DOMAIN: ${LOCAL_DOMAIN:-localhost:3000} + VITE_DEV_SERVER_PUBLIC: ${VITE_DEV_SERVER_PUBLIC:-localhost:3036} # Overrides default command so things don't shut down after the process ends. command: sleep infinity ports: - '3000:3000' - - '3035:3035' + - '3036:3036' - '4000:4000' networks: - external_network diff --git a/.env.development b/.env.development index 0330da8377..345737ac6e 100644 --- a/.env.development +++ b/.env.development @@ -2,3 +2,5 @@ ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr + +MASTODON_USE_LIBVIPS=false diff --git a/.env.production.sample b/.env.production.sample index 4afaf8d756..15004b9d0d 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -43,7 +43,6 @@ ES_PASS=password # Make sure to use `bundle exec rails secret` to generate secrets # ------- SECRET_KEY_BASE= -OTP_SECRET= # Encryption secrets # ------------------ diff --git a/.github/ISSUE_TEMPLATE/3.troubleshooting.yml b/.github/ISSUE_TEMPLATE/3.troubleshooting.yml index fa9bfc7c80..004e74bf42 100644 --- a/.github/ISSUE_TEMPLATE/3.troubleshooting.yml +++ b/.github/ISSUE_TEMPLATE/3.troubleshooting.yml @@ -50,7 +50,7 @@ body: label: Mastodon version description: | This is displayed at the bottom of the About page, eg. `v4.4.0-alpha.1` - placeholder: v4.3.0 + placeholder: v4.4.0-beta.1 validations: required: false - type: textarea @@ -60,9 +60,9 @@ body: Details about your environment, like how Mastodon is deployed, if containers are used, version numbers, etc. value: | Please at least include those informations: - - Operating system: (eg. Ubuntu 22.04) - - Ruby version: (from `ruby --version`, eg. v3.4.1) - - Node.js version: (from `node --version`, eg. v20.18.0) + - Operating system: (eg. Ubuntu 24.04.2) + - Ruby version: (from `ruby --version`, eg. v3.4.4) + - Node.js version: (from `node --version`, eg. v22.16.0) validations: required: false - type: textarea diff --git a/.github/renovate.json5 b/.github/renovate.json5 index e638b9c548..1850a45bbc 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -25,26 +25,12 @@ 'tesseract.js', // Requires code changes 'react-hotkeys', // Requires code changes - // Requires Webpacker upgrade or replacement - '@svgr/webpack', - '@types/webpack', - 'babel-loader', - 'compression-webpack-plugin', - 'css-loader', - 'imports-loader', - 'mini-css-extract-plugin', - 'postcss-loader', - 'sass-loader', - 'terser-webpack-plugin', - 'webpack', - 'webpack-assets-manifest', - 'webpack-bundle-analyzer', - 'webpack-dev-server', - 'webpack-cli', - // react-router: Requires manual upgrade 'history', 'react-router-dom', + + // react-spring: Requires manual upgrade when upgrading react + '@react-spring/web', ], matchUpdateTypes: ['major'], dependencyDashboardApproval: true, @@ -53,7 +39,6 @@ // Require Dependency Dashboard Approval for major version bumps of these Ruby packages matchManagers: ['bundler'], matchPackageNames: [ - 'rack', // Needs to be synced with Rails version 'strong_migrations', // Requires manual upgrade 'sidekiq', // Requires manual upgrade 'sidekiq-unique-jobs', // Requires manual upgrades and sync with Sidekiq version diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml new file mode 100644 index 0000000000..4e6179bc77 --- /dev/null +++ b/.github/workflows/chromatic.yml @@ -0,0 +1,41 @@ +name: 'Chromatic' + +on: + push: + branches-ignore: + - renovate/* + - stable-* + paths: + - 'package.json' + - 'yarn.lock' + - '**/*.js' + - '**/*.jsx' + - '**/*.ts' + - '**/*.tsx' + - '**/*.css' + - '**/*.scss' + - '.github/workflows/chromatic.yml' + +jobs: + chromatic: + name: Run Chromatic + runs-on: ubuntu-latest + if: github.repository == 'mastodon/mastodon' + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Javascript environment + uses: ./.github/actions/setup-javascript + + - name: Build Storybook + run: yarn build-storybook + + - name: Run Chromatic + uses: chromaui/action@v12 + with: + # ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + zip: true + storybookBuildDir: 'storybook-static' diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml index f962f5c36f..6164210253 100644 --- a/.github/workflows/test-js.yml +++ b/.github/workflows/test-js.yml @@ -43,4 +43,4 @@ jobs: uses: ./.github/actions/setup-javascript - name: JavaScript testing - run: yarn jest --reporters github-actions summary + run: yarn test:js diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index fd4c666059..fefe674f44 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -52,7 +52,7 @@ jobs: public/assets public/packs public/packs-test - tmp/cache/webpacker + tmp/cache/vite key: ${{ matrix.mode }}-assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }} restore-keys: | ${{ matrix.mode }}-assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }} @@ -66,7 +66,7 @@ jobs: - name: Archive asset artifacts run: | - tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs* + tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs* tmp/cache/vite/last-build*.json - uses: actions/upload-artifact@v4 if: matrix.mode == 'test' @@ -147,7 +147,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg imagemagick libpam-dev + additional-system-dependencies: ffmpeg libpam-dev - name: Load database schema run: | @@ -177,8 +177,8 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - test-libvips: - name: Libvips tests + test-imagemagick: + name: ImageMagick tests runs-on: ubuntu-latest needs: @@ -224,7 +224,7 @@ jobs: CAS_ENABLED: true BUNDLE_WITH: 'pam_authentication test' GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }} - MASTODON_USE_LIBVIPS: true + MASTODON_USE_LIBVIPS: false strategy: fail-fast: false @@ -249,7 +249,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg libpam-dev + additional-system-dependencies: ffmpeg imagemagick libpam-dev - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' @@ -329,7 +329,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg imagemagick + additional-system-dependencies: ffmpeg - name: Set up Javascript environment uses: ./.github/actions/setup-javascript @@ -337,6 +337,21 @@ jobs: - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' + - name: Cache Playwright Chromium browser + id: playwright-cache + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + + - name: Install Playwright Chromium browser (with deps) + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: yarn run playwright install --with-deps chromium + + - name: Install Playwright Chromium browser deps + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: yarn run playwright install-deps chromium + - run: bin/rspec spec/system --tag streaming --tag js - name: Archive logs @@ -350,7 +365,7 @@ jobs: uses: actions/upload-artifact@v4 if: failure() with: - name: e2e-screenshots + name: e2e-screenshots-${{ matrix.ruby-version }} path: tmp/capybara/ test-search: @@ -448,7 +463,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg imagemagick + additional-system-dependencies: ffmpeg - name: Set up Javascript environment uses: ./.github/actions/setup-javascript diff --git a/.gitignore b/.gitignore index 7d60baebf8..95a8f19a45 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,11 @@ /public/system /public/assets /public/packs +/public/packs-dev /public/packs-test .env .env.production -/node_modules/ +node_modules/ /build/ # Ignore elasticsearch config @@ -77,3 +78,6 @@ docker-compose.override.yml # Ignore local-only rspec configuration .rspec-local + +*storybook.log +storybook-static diff --git a/.nvmrc b/.nvmrc index 744ca17ec0..f2a2bc6165 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.14 +22.16 diff --git a/.prettierignore b/.prettierignore index 80b4c0159e..8f16e731c8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -18,10 +18,6 @@ !/log/.keep /tmp /coverage -/public/system -/public/assets -/public/packs -/public/packs-test .env .env.production .env.development @@ -60,10 +56,11 @@ docker-compose.override.yml /public/packs /public/packs-test /public/system +/public/vite* # Ignore emoji map file /app/javascript/mastodon/features/emoji/emoji_map.json -/app/javascript/mastodon/features/emoji/emoji_sheet.json +/app/javascript/mastodon/features/emoji/emoji_data.json # Ignore locale files /app/javascript/mastodon/locales/*.json diff --git a/.rubocop/naming.yml b/.rubocop/naming.yml index da6ad4ac57..37d3a17efd 100644 --- a/.rubocop/naming.yml +++ b/.rubocop/naming.yml @@ -1,3 +1,6 @@ --- Naming/BlockForwarding: EnforcedStyle: explicit + +Naming/PredicateMethod: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 13fb25d333..47d77d226a 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --no-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.75.2. +# using RuboCop version 1.76.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -31,58 +31,14 @@ Metrics/PerceivedComplexity: - 'app/services/delivery_antenna_service.rb' - 'app/services/post_status_service.rb' -Rails/OutputSafety: - Exclude: - - 'config/initializers/simple_form.rb' - # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowedVars. Style/FetchEnvVar: Exclude: - - 'config/environments/production.rb' - 'config/initializers/2_limited_federation_mode.rb' - - 'config/initializers/3_omniauth.rb' - - 'config/initializers/cache_buster.rb' - - 'config/initializers/devise.rb' - 'config/initializers/paperclip.rb' - - 'config/initializers/vapid.rb' - - 'lib/tasks/repo.rake' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns. -# SupportedStyles: annotated, template, unannotated -# AllowedMethods: redirect -Style/FormatStringToken: - Exclude: - - 'config/initializers/devise.rb' - - 'lib/paperclip/color_extractor.rb' # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. Style/GuardClause: Enabled: false - -# Configuration parameters: AllowedMethods. -# AllowedMethods: respond_to_missing? -Style/OptionalBooleanParameter: - Exclude: - - 'app/lib/admin/system_check/message.rb' - - 'app/lib/request.rb' - - 'app/lib/webfinger.rb' - - 'app/services/block_domain_service.rb' - - 'app/services/fetch_resource_service.rb' - - 'app/workers/domain_block_worker.rb' - - 'app/workers/unfollow_follow_worker.rb' - -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: short, verbose -Style/PreferredHashMethods: - Exclude: - - 'config/initializers/paperclip.rb' - -# This cop supports safe autocorrection (--autocorrect). -Style/RedundantConstantBase: - Exclude: - - 'config/environments/production.rb' - - 'config/initializers/sidekiq.rb' diff --git a/.ruby-version b/.ruby-version index 6cb9d3dd0d..f9892605c7 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.4.3 +3.4.4 diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 0000000000..638806c085 --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,16 @@ +import type { StorybookConfig } from '@storybook/react-vite'; + +const config: StorybookConfig = { + stories: ['../app/javascript/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + '@storybook/addon-docs', + '@storybook/addon-a11y', + '@storybook/addon-vitest', + ], + framework: { + name: '@storybook/react-vite', + options: {}, + }, +}; + +export default config; diff --git a/.storybook/manager.ts b/.storybook/manager.ts new file mode 100644 index 0000000000..53dfaa15ab --- /dev/null +++ b/.storybook/manager.ts @@ -0,0 +1,7 @@ +import { addons } from 'storybook/manager-api'; + +import theme from './storybook-theme'; + +addons.setConfig({ + theme, +}); diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html new file mode 100644 index 0000000000..0a4f196752 --- /dev/null +++ b/.storybook/preview-head.html @@ -0,0 +1,18 @@ + diff --git a/.storybook/preview.ts b/.storybook/preview.ts new file mode 100644 index 0000000000..a0bec9085f --- /dev/null +++ b/.storybook/preview.ts @@ -0,0 +1,29 @@ +import type { Preview } from '@storybook/react-vite'; + +// If you want to run the dark theme during development, +// you can change the below to `/application.scss` +import '../app/javascript/styles/mastodon-light.scss'; + +const preview: Preview = { + // Auto-generate docs: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + layout: 'centered', + + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + + a11y: { + // 'todo' - show a11y violations in the test UI only + // 'error' - fail CI on a11y violations + // 'off' - skip a11y checks entirely + test: 'todo', + }, + }, +}; + +export default preview; diff --git a/.storybook/storybook-addon-vitest.d.ts b/.storybook/storybook-addon-vitest.d.ts new file mode 100644 index 0000000000..86852faca9 --- /dev/null +++ b/.storybook/storybook-addon-vitest.d.ts @@ -0,0 +1,7 @@ +// The addon package.json incorrectly exports types, so we need to override them here. +// See: https://github.com/storybookjs/storybook/blob/v9.0.4/code/addons/vitest/package.json#L70-L76 +declare module '@storybook/addon-vitest/vitest-plugin' { + export * from '@storybook/addon-vitest/dist/vitest-plugin/index'; +} + +export {}; diff --git a/.storybook/storybook-theme.ts b/.storybook/storybook-theme.ts new file mode 100644 index 0000000000..7a72ba1c75 --- /dev/null +++ b/.storybook/storybook-theme.ts @@ -0,0 +1,7 @@ +import { create } from 'storybook/theming'; + +export default create({ + base: 'light', + brandTitle: 'Mastodon Storybook', + brandImage: 'https://joinmastodon.org/logos/wordmark-black-text.svg', +}); diff --git a/.storybook/vitest.setup.ts b/.storybook/vitest.setup.ts new file mode 100644 index 0000000000..a08badd02f --- /dev/null +++ b/.storybook/vitest.setup.ts @@ -0,0 +1,8 @@ +import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview'; +import { setProjectAnnotations } from '@storybook/react-vite'; + +import * as projectAnnotations from './preview'; + +// This is an important step to apply the right configuration when testing your stories. +// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations +setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]); diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd4783597..de5ccfb325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,290 @@ All notable changes to this project will be documented in this file. +## [4.4.0] - UNRELEASED + +### Added + +- **Add “Followers you know” widget to user profiles and hover cards** (#34652, #34678, #34681, #34697, #34699, #34769, #34774 and #34914 by @diondiondion) +- **Add featured tab to profiles on web UI and rework pinned posts** (#34405, #34483, #34491, #34754, #34855, #34858, #34868, and #34869 by @ChaosExAnima, @ClearlyClaire, @Gargron, and @diondiondion) +- Add endorsed accounts to featured tab in web UI (#34421 and #34568 by @Gargron)\ + This also includes the following new REST API endpoints: + - `GET /api/v1/accounts/:id/endorsements`: https://docs.joinmastodon.org/methods/accounts/#endorsements + - `POST /api/v1/accounts/:id/endorse`: https://docs.joinmastodon.org/methods/accounts/#endorse + - `POST /api/v1/accounts/:id/unendorse`: https://docs.joinmastodon.org/methods/accounts/#unendorse +- Add ability to add and remove hashtags from featured tags in web UI (#34489, #34887, and #34490 by @ClearlyClaire and @Gargron)\ + This is achieved through the new REST API endpoints: + - `POST /api/v1/tags/:id/feature`: https://docs.joinmastodon.org/methods/tags/#feature + - `POST /api/v1/tags/:id/unfeature`: https://docs.joinmastodon.org/methods/tags/#unfeature +- Add reminder when about to post without alt text in web UI (#33760 and #33784 by @Gargron) +- Add a warning in Web UI when composing a post when the selected and detected language are different (#33042, #33683, #33700, #33724, #33770, and #34193 by @ClearlyClaire and @Gargron) +- Add ability to reorder and translate server rules (#34637, #34737, #34494, #34756, and #34820 by @ChaosExAnima and @ClearlyClaire)\ + Rules are now shown in the user’s language, if a translation has been set.\ + In the REST API, `Rule` entities now have a new `translations` attribute: https://docs.joinmastodon.org/entities/Rule/#translations +- Add emoji from Twemoji 15.1.0, including in the emoji picker/completion (#33395, #34321, #34620, and #34677 by @ChaosExAnima, @ClearlyClaire, @TheEssem, and @eramdam) +- Add experimental support for verifying and displaying remote quote posts (#34370, #34481, #34510, #34551, #34480, #34479, #34553, #34584, #34623, #34738, #34766, #34770, #34772, #34773, #34786, #34790, and #34864 by @ClearlyClaire and @diondiondion)\ + Support for verifying remote quotes according to [FEP-044f](https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md) and displaying them in the Web UI has been implemented. Such quotes are currently only processed if the `inbound_quotes` experimental feature is enabled (`EXPERIMENTAL_FEATURES=inbound_quotes`).\ + Quoting other people is not implemented yet, and it is currently not possible to mark your own posts as allowing quotes. However, a new “Who can quote” setting has been added to the “Posting defaults” section of the user settings. This setting allows you to set a default that will be used for new posts made on Mastodon 4.5 and newer, when quote posts will be fully implemented.\ + In the REST API, quote posts are represented by a new `quote` attribute on `Status` and `StatusEdit` entities: https://docs.joinmastodon.org/entities/StatusEdit/#quote https://docs.joinmastodon.org/entities/Status/#quote +- Add option to remove account from followers in web UI (#34488 by @Gargron) +- Add relationship tags to profiles and hover cards in web UI (#34467 and #34792 by @Gargron and @diondiondion) +- Add ability to open posts in a new tab by middle-clicking in web UI (#32988, #33106, #33419, and #34700 by @ClearlyClaire, @Gargron, and @tribela) +- Add new filter action to blur media (#34256 by @ClearlyClaire)\ + In the REST API, this adds a new possible value of `blur` to the `filter_action` attribute: https://docs.joinmastodon.org/entities/Filter/#filter_action +- Add dropdown menu to hashtag links in web UI (#34393 by @Gargron) +- **Add server setting to allow referrer** (#33214, #33239, #33903, and #34731 by @ChaosExAnima, @ClearlyClaire, @Gargron, and @renchap)\ + In order to protect the privacy of users of small or thematic servers, Mastodon previously avoided transmitting referrer information when clicking outside links, which unfortunately made Mastodon completely invisible to other websites, even though the privacy implications on large generic servers are very limited.\ + Server administrators can now chose to opt in to transmit referrer information when following an external link. Only the domain name is transmitted, not the referrer path. +- Add double tap to zoom and swipe to dismiss to media modal in web UI (#34210 by @Gargron) +- Add link from Web UI for Hashtags to the Moderation UI (#31448 by @ThisIsMissEm) +- **Add terms of service** (#33055, #33233, #33230, #33703, #33699, #33994, #33993, #34105, #34122, #34200, and #34527 by @ClearlyClaire, @Gargron, @mjankowski, and @oneiros)\ + Server administrators can now fill in Terms of Service, optionally using a provided template. +- **Add age verification on sign-up** (#34150, #34663, and #34636 by @ClearlyClaire and @Gargron)\ + Server administrators now have a setting to set a minimum age requirement for creating a new server, asking users for their date of birth. The date of birth is checked against the minimum age requirement server-side but not stored.\ + The following REST API changes have been made to accommodate this: + - `registrations.min_age` has been added to the `Instance` entity: https://docs.joinmastodon.org/entities/Instance/#registrations-min_age + - the `date_of_birth` parameter has been added to the account creation API: https://docs.joinmastodon.org/methods/accounts/#create +- Add ability to dismiss alt text badge by tapping it in web UI (#33737 by @Gargron) +- Add loading indicator to timeline gap indicators in web UI (#33762 by @Gargron) +- Add interaction modal when trying to interact with a poll while logged out (#32609 by @ThisIsMissEm) +- **Add experimental FASP support** (#34031, #34415, and #34765 by @oneiros)\ + This is a first step towards supporting “Fediverse Auxiliary Service Providers” (https://github.com/mastodon/fediverse_auxiliary_service_provider_specifications). This is mostly interesting to developers who would like to implement their own FASP, but also includes the capability to share data with a discovery provider (see https://www.fediscovery.org). +- Add ability for admins to send announcements to all users via email (#33928 and #34411 by @ClearlyClaire)\ + This is meant for critical announcements only, as this will potentially send a lot of emails and cannot be opted out of by users. +- Add option to use system scrollbar styling (#32117 by @vmstan) +- Add hover cards to follow suggestions (#33749 by @ClearlyClaire) +- Add `t` hotkey for post translations (#33441 by @ClearlyClaire) +- Add timestamp to all announcements in Web UI (#18329 by @ClearlyClaire) +- Add dropdown menu with quick actions to lists of accounts in web UI (#34391, #34709, and #34767 by @Gargron, @diondiondion, and @mkljczk) +- Add support for displaying “year in review” notification in web UI (#32710, #32765, #32709, #32807, #32914, #33148, and #33882 by @Gargron and @mjankowski)\ + Note that the notification is currently not generated automatically, and at the moment requires a manual undocumented administrator action. +- Add experimental support for receiving HTTP Message Signatures (RFC9421) (#34814 by @oneiros)\ + For now, this needs to be explicitly enabled through the `http_message_signatures` feature flag (`EXPERIMENTAL_FEATURES=http_message_signatures`). This currently only covers verifying such signatures (inbound HTTP requests), not issuing them (outbound HTTP requests). +- Add experimental server-side feature to fetch remote replies (#32615, #34147, #34149, #34151, #34615, #34682, and #34702 by @ClearlyClaire and @sneakers-the-rat)\ + This experimental feature causes the server to recursively fetch replies in background tasks whenever a user opens a remote post. This happens asynchronously and the client is currently not notified of the existence of new replies, which will thus only be displayed the next time this post’s context gets requested.\ + This feature needs to be explicitly enabled server-side by setting `FETCH_REPLIES_ENABLED` environment variable to `true`. +- Add simple feature flag system through the `EXPERIMENTAL_FEATURES` environment variable (#34038 and #34124 by @oneiros)\ + This allows enabling comma-separated feature flags for experimental features.\ + The current supported feature flags are `inbound_quotes`, `fasp` and `http_message_signatures`. +- Add `dev:populate_sample_data` rake task to populate test data (#34676, #34733, #34771, #34787, and #34791 by @ClearlyClaire and @diondiondion) +- Add support for displaying fallback representation when receiving MathML (#27107 by @4e554c4c) +- Add warning for Elasticsearch index analyzers mismatch (#34515 and #34567 by @ClearlyClaire and @Gargron) +- Add `-only-mapping` option to `tootctl search deploy` (#34466 and #34566 by @Gargron) +- Add server-side support for grouping account sign-up notifications (#34298 by @ClearlyClaire) +- Add `registrations.reason_required` attribute to `/api/v2/instance` response (#34280 by @ClearlyClaire)\ + This is documented at https://docs.joinmastodon.org/entities/Instance/#registrations-reason_required +- Add `EXTRA_MEDIA_HOSTS` environment variable to add extra hosts to Content-Security-Policy (#34184 by @shleeable) +- Add `Deprecation` headers on deprecated API endpoints (#34262 and #34397 by @ClearlyClaire)\ + This is documented at https://docs.joinmastodon.org/api/guidelines/#deprecations +- Add `about`, `privacy_policy` and `terms_of_service` URLs to `/api/v2/instance` (#33849 by @ClearlyClaire) +- Add API to delete media attachments that are not in use (#33991 and #34035 by @ClearlyClaire and @ThisIsMissEm)\ + `DELETE /api/v1/media/:id`: https://docs.joinmastodon.org/methods/media/#delete +- Add optional `delete_media` parameter to `DELETE /api/v1/statuses/:id` (#33988 by @ClearlyClaire)\ + This is documented at https://docs.joinmastodon.org/methods/statuses/#delete +- Add `og:locale` to expose status language in OpenGraph previews (#34012 by @ThisIsMissEm) +- Add `-skip-filled-timeline` option to `tootctl feed build` to skip half-filled feeds (#33844 by @ClearlyClaire) +- Add support for changing the base Docker registry with the `BASE_REGISTRY` `ARG` (#33712 by @wolfspyre) +- Add an optional metric exporter (#33734, #33840, #34172, #34192, 34223)\ + Optionally enable the `prometheus_exporter` ruby gem (see https://github.com/discourse/prometheus_exporter) to collect and expose metrics. See the documentation for all the details: https://docs.joinmastodon.org/admin/config/#prometheus +- Add `attribution_domains` attribute to `PATCH /api/v1/accounts/update_credentials` (#32730 by @c960657)\ + This is documented at https://docs.joinmastodon.org/methods/accounts/#update_credentials +- Add support for standard WebPush in addition to previous draft (#33572, #33528, and #33587 by @ClearlyClaire and @p1gp1g) +- Add support for Active Record query log tags (#33342 by @renchap) +- Add OTel trace & span IDs to logs (#33339 and #33362 by @renchap) +- Add missing `on_delete: :cascade` foreign keys option to various database columns (#33175 by @mjankowski) +- Add explicit migration breakpoints (#33089 by @ClearlyClaire) +- Add rel alternate rss/json links to pages for tags (#33179 by @mjankowski) +- Add media attachment description limit to instance API response (#33153 by @mjankowski)\ + This adds the `configuration.media_attachments.description_limit` attribute to the `Instance` entity, documented at https://docs.joinmastodon.org/entities/Instance/#description_limit +- Add `maxlength` to registration reason input (#33162 by @mjankowski) +- Add `REPLICA_PREPARED_STATEMENTS` and `REPLICA_DB_TASKS` environment variables (#32908 by @shleeable)\ + See documentation at https://docs.joinmastodon.org/admin/scaling/#read-replicas +- Add a range of reserved usernames to reduce potential misuse by malicious actors (#32828 by @jmking-iftas) +- Add operations on relays to the admin audit log (#32819 by @ThisIsMissEm) +- Add userinfo OAuth endpoint (#32548 by @ThisIsMissEm) +- Add the standard VCS attributes to OpenTelemetry spans (#32904 by @renchap) +- Add endpoint to remove web push subscription (#32626 by @oneiros)\ + Mastodon now sets a new `Unsubscribe-URL` request header when performing WebPush requests. This URL can be used by the WebPush server to disable the WebPush subscription on Mastodon’s side in case of unfixable errors. +- Add missing content warning text to RSS feeds (#32406 by @mjankowski) +- Add Swiss German to languages dropdown (#29281 by @FlohEinstein) + +### Changed + +- Change design of lists in web UI (#32881, #33054, and #33036 by @Gargron) +- Change design of edit media modal in web UI (#33516, #33702, #33725, #33725, #33771, and #34345 by @Gargron) +- Change design of audio player in web UI (#34520, #34740, and #34865 by @ClearlyClaire, @Gargron, and @diondiondion) +- Change design of interaction modal in web UI (#33278 by @Gargron) +- Change list timelines to reflect added and removed users retroactively (#32930 by @Gargron) +- Change account search to be more forgiving of spaces (#34455 by @Gargron) +- Change unfollow button label from “Mutual” to “Unfollow” in web UI (#34392 by @Gargron) +- Change “Specific people” to “Private mention” in menu in web UI (#33963 by @Gargron) +- Change language names in compose box language picker to be localized (#33402 by @c960657) +- Change onboarding flow in web UI (#32998, #33119, and #33471 by @ClearlyClaire and @Gargron) +- Change emoji categories in admin interface to be ordered by name (#33630 by @ShadowJonathan) +- Change design of rich text elements in web UI (#32633 by @Gargron) +- Change wording of “single choice” to “pick one” in poll authoring form (#32397 by @ThisIsMissEm) +- Change returned favorite and boost counts to use those provided by the remote server, if available (#32620, #34594, #34618, and #34619 by @ClearlyClaire and @sneakers-the-rat) +- Change label of favourite notifications on private mentions (#31659 by @ClearlyClaire) +- Change `libvips` to be enabled by default in place of ImageMagick (#34741 and #34753 by @ClearlyClaire and @diondiondion) +- Change avatar and header size limits from 2MB to 8MB when using libvips (#33002 by @Gargron) +- Change search to use query params in web UI (#32949 and #33670 by @ClearlyClaire and @Gargron) +- Change build system from Webpack to Vite (#34454, #34450, #34758, #34768, #34813, #34808, #34837, and #34732 by @ChaosExAnima, @ClearlyClaire, @mjankowski, and @renchap)\ + One known limitation is that themes’ main style file needs to have a very specific file name: `app/javascript/styles/:name.scss` where `:name` is the name of the theme in `config/themes.yml` +- Change account creation API to forbid creation from user tokens (#34828 by @ThisIsMissEm) +- Change `/api/v2/instance` to be enabled without authentication when limited federation mode is enabled (#34576 by @ClearlyClaire) +- Change `DEFAULT_LOCALE` to not override unauthenticated users’ browser language (#34535 by @ClearlyClaire)\ + If you want to preserve the old behavior, you can add `FORCE_DEFAULT_LOCALE=true`. +- Change size of profile picture on profile page from 90px to 92px (#34807 by @larouxn) +- Change passthrough video processing to emit `moov` atom at start of video (#34726 by @ClearlyClaire) +- Change kerning to be disabled for Japanese text to preserve monospaced alignment for readability (#34448 by @nagutabby) +- Change error handling of various endpoints to return 422 instead of 500 on invalid parameters (#29308, #34434, and #34452 by @danielmbrasil and @mjankowski) +- Change Web UI to use `