Compare commits

..

598 Commits

Author SHA1 Message Date
Claire
6c6ea030f4 Merge pull request #3317 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to ff20ab7510
2025-12-19 09:16:38 +01:00
Echo
9ce81baff9 [Glitch] Emoji loading fixes
Port ba4710debe to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-18 18:59:46 +01:00
Claire
baa6af0e18 Merge commit 'ff20ab7510a189bee75bdd5460f6c2ae38e7009a' into glitch-soc/merge-upstream 2025-12-18 18:56:31 +01:00
Echo
ff20ab7510 Fixes CDN domain loading (#37310) 2025-12-18 17:41:21 +00:00
Claire
4bfd92310f [Glitch] Fix custom emojis not displaying in CWs and fav/boost notifications
Port a8109e50fc to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-18 18:11:41 +01:00
Claire
97ff0f94bf Merge commit 'a8109e50fc313b8124a3e471d41b490df59a68b8' into glitch-soc/merge-upstream
Conflicts:
- `app/views/settings/preferences/appearance/show.html.haml`:
  Upstream changed a field that was moved to another page due to glitch-soc's theming system.
  Ignored this one change.
2025-12-18 18:10:30 +01:00
Echo
ba4710debe Emoji loading fixes (#37300) 2025-12-18 16:58:44 +00:00
Claire
a8109e50fc Fix custom emojis not displaying in CWs and fav/boost notifications (#37306) 2025-12-18 16:49:03 +00:00
Claire
2a7e5fb3f7 Skip followers synchronization for accounts with 25k followers or more (#37302) 2025-12-18 14:42:47 +00:00
renovate[bot]
8bc0170c02 Update docker.io/ruby Docker tag to v3.4.8 (#37297)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 14:42:07 +00:00
renovate[bot]
787b00813e Update dependency ruby to v3.4.8 (#37278)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 14:41:35 +00:00
Claire
ffdf56b1e6 Fix default Admin role not including view_feeds permission (#37301) 2025-12-18 14:26:31 +00:00
Joshua Rogers
38bc7d2864 Use HTTPS when downloading unicode.org's emoji-test.txt (#37290) 2025-12-18 10:11:54 +00:00
github-actions[bot]
ed2a8c32ce New Crowdin Translations (automated) (#37293)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-18 09:20:07 +00:00
diondiondion
830ffbe2da Remove required field markers from unclearable fields in user preferences (#37291) 2025-12-18 08:58:06 +00:00
Echo
177d3c59d0 [Glitch] Emoji: Refresh custom emoji on new
Port 3d55dcdf7f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-17 18:34:02 +01:00
diondiondion
392a241637 [Glitch] Improve search menu keyboard navigation
Port c4a760d6ba to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-17 18:32:57 +01:00
Echo
34dbea26a7 [Glitch] Remove rendering of custom emoji using the database
Port dbc5af6641 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-17 18:32:34 +01:00
diondiondion
516f0ce131 [Glitch] Fix notifications page error in Tor browser
Port 71af094f97 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-17 18:31:49 +01:00
Claire
22724d2367 [Glitch] Fix hashtag autocomplete replacing suggestion's first characters with input
Port d6a40c2891 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-17 18:31:31 +01:00
Claire
84feffd6e6 Merge commit '009275e66b55729f754da7b4c814b37b67dc76dc' into glitch-soc/merge-upstream
Conflicts:
- `app/models/form/admin_settings.rb`:
  Upstream added a method right next to glitch-soc-only methods.
  Added upstream's method.
- `app/views/settings/preferences/appearance/show.html.haml`:
  Upstream changed a line right next to a glitch-soc addition.
  Changed the code as upstream did.
2025-12-17 18:27:14 +01:00
Matt Jankowski
009275e66b Use link_to for contribute translation link (#36011) 2025-12-17 15:19:21 +00:00
Echo
3d55dcdf7f Emoji: Refresh custom emoji on new (#37271) 2025-12-17 14:58:22 +00:00
Matt Jankowski
7e817f2471 Extract filter_keywords helper method for listing filter keyword groups (#35921) 2025-12-17 14:48:58 +00:00
diondiondion
c4a760d6ba Improve search menu keyboard navigation (#37255) 2025-12-17 14:42:07 +00:00
Echo
dbc5af6641 Remove rendering of custom emoji using the database (#37284) 2025-12-17 14:40:34 +00:00
diondiondion
71af094f97 Fix notifications page error in Tor browser (#37285) 2025-12-17 14:38:46 +00:00
Claire
d6a40c2891 Fix hashtag autocomplete replacing suggestion's first characters with input (#37281) 2025-12-17 14:28:53 +00:00
Nicholas La Roux
a5362a4002 Upgrade Bundler from 4.0.1 to 4.0.2 (#37283) 2025-12-17 14:06:45 +00:00
renovate[bot]
42d4753d30 Update dependency vite-tsconfig-paths to v6.0.2 (#37279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-17 13:15:05 +00:00
github-actions[bot]
8debc5760b New Crowdin Translations (automated) (#37174)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-17 11:18:17 +00:00
David Roetzel
5e8b8f9c23 Extract interaction policy class (#37277) 2025-12-17 10:12:43 +00:00
Claire
db62d70492 Change Wrapstodon switch from feature flag to admin setting (#37273) 2025-12-17 09:47:02 +00:00
Matt Jankowski
a292162c5f Mark Form::AdminSettings#persisted? as true (#35872) 2025-12-17 08:32:24 +00:00
Claire
6c2d53372b Merge pull request #3316 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 53be8392ec
2025-12-16 19:09:07 +01:00
diondiondion
cfc64a2ea9 [Glitch] Updates Wrapstodon footer with dedicated local server info
Port e6b0cdcc83 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-16 18:37:45 +01:00
Echo
fbacb5ae7a [Glitch] Emojis: Show in embedded statuses
Port f118d61334 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-16 18:32:54 +01:00
Echo
f56f360a5c [Glitch] Wrapstodon: Load report data only on display
Port a9c84529b2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-16 18:32:30 +01:00
diondiondion
59d2a712c5 [Glitch] Fix bad contrast on disabled dropdown menu items
Port 9e97ad04d8 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-16 18:31:01 +01:00
Echo
177479fe37 [Glitch] Improve Redux Storybook
Port 8c2845906c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-16 18:30:39 +01:00
Claire
3cd033df0c [Glitch] Add wrapstodon to initial state and show wrapstodon sidebar item on load
Port 550a6d4765 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-16 18:29:51 +01:00
Claire
780fefa700 Merge commit '53be8392eceea8c3a576478e209fe82c2ceb458a' into glitch-soc/merge-upstream 2025-12-16 18:27:03 +01:00
Matt Jankowski
53be8392ec Add coverage for blocked account scenario in following/followers (#36042) 2025-12-16 16:13:03 +00:00
Echo
f118d61334 Emojis: Show in embedded statuses (#37272) 2025-12-16 16:06:59 +00:00
Matt Jankowski
95432b47eb Add coverage for user model registration time validation (#35993) 2025-12-16 15:58:39 +00:00
Matt Jankowski
dbf8d77cbb Add spec for missing username value in create account API (#37057) 2025-12-16 15:43:04 +00:00
diondiondion
e6b0cdcc83 Updates Wrapstodon footer with dedicated local server info (#37270) 2025-12-16 15:35:26 +00:00
Matt Jankowski
7e81e03531 Reduce factory creation across spec/helpers (#35527) 2025-12-16 15:26:04 +00:00
Matt Jankowski
92df1c4458 Add coverage for Account.representative from finder concern (#35996) 2025-12-16 15:05:26 +00:00
Echo
a9c84529b2 Wrapstodon: Load report data only on display (#37269) 2025-12-16 13:00:40 +00:00
diondiondion
9e97ad04d8 Fix bad contrast on disabled dropdown menu items (#37268) 2025-12-16 11:38:47 +00:00
Echo
8c2845906c Improve Redux Storybook (#37227) 2025-12-16 11:27:18 +00:00
Matt Jankowski
7230c2059f Add coverage for "domain variants" consumers (#35995) 2025-12-16 10:24:27 +00:00
Matt Jankowski
c8f608839b Use bundler version 4.0.1 (#37191) 2025-12-16 10:13:43 +00:00
Claire
550a6d4765 Add wrapstodon to initial state and show wrapstodon sidebar item on load (#37261) 2025-12-16 09:47:18 +00:00
renovate[bot]
4c679c698f Update dependency vite-tsconfig-paths to v6 (#37247)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 09:46:39 +00:00
renovate[bot]
71821eb9c1 Update dependency tzinfo-data to v1.2025.3 (#37242)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 09:45:59 +00:00
Claire
0801104729 Fix mentions of domain-blocked users being processed (#37257) 2025-12-16 08:49:48 +00:00
Claire
57554e9e33 Merge pull request #3315 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to cbe1352103
2025-12-15 22:18:41 +01:00
renovate[bot]
0551455a3c [Glitch] Update devDependencies (non-major)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: ChaosExAnima <ChaosExAnima@users.noreply.github.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-15 20:38:29 +01:00
Echo
460e675327 [Glitch] Emoji: Import and use shortcode data
Port cbe1352103 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-15 20:30:02 +01:00
diondiondion
5aaf5f2256 [Glitch] Prevent "invalid access token" error when opening Mastodon while logged out
Port 807e1254e6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-15 20:28:14 +01:00
Echo
56a9d62972 [Glitch] Fixes display names not rendering with emojis
Port 5fa7654688 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-15 20:27:54 +01:00
diondiondion
0c852a426f [Glitch] Fix badly visible focus outlines in composer
Port a9e228361c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-15 20:27:02 +01:00
Claire
1fdb48c668 Merge commit 'cbe135210305c0ce4455130c4e75680e53ff1425' into glitch-soc/merge-upstream
Conflicts:
- `app/views/wrapstodon/show.html.haml`:
  Conflict caused by glitch-soc's theming system.
  Updated upstream changes.
2025-12-15 20:22:20 +01:00
Echo
cbe1352103 Emoji: Import and use shortcode data (#37178) 2025-12-15 15:38:13 +00:00
David Roetzel
a3fa441e0c Check "featureable" policy on creation of collections (#37254) 2025-12-15 15:29:28 +00:00
diondiondion
807e1254e6 Prevent "invalid access token" error when opening Mastodon while logged out (#37256) 2025-12-15 15:24:03 +00:00
Isa S.
9d18df4f8a Add REPLICA_DB_HOST to replica_enabled helper (#37240) 2025-12-15 13:25:42 +00:00
Nicholas La Roux
09ab2829da Upgrade rubocop-rails from 2.33.4 to 2.34.2 and address related offenses (#37243) 2025-12-15 12:57:16 +00:00
Echo
5fa7654688 Fixes display names not rendering with emojis (#37251) 2025-12-15 12:54:46 +00:00
renovate[bot]
2984f377e8 Update devDependencies (non-major) (#37074)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: ChaosExAnima <ChaosExAnima@users.noreply.github.com>
2025-12-15 12:53:21 +00:00
diondiondion
a9e228361c Fix badly visible focus outlines in composer (#37250) 2025-12-15 12:39:04 +00:00
renovate[bot]
d7f632f6ba Update dependency tesseract.js to v7 (#37246)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 12:07:57 +00:00
Claire
dc4fb51e52 Increase cache duration on public shared wrapstodon page (#37249) 2025-12-15 10:19:17 +00:00
renovate[bot]
c112c6d3a2 Update Node.js to 24.12 (#37196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 08:03:56 +00:00
renovate[bot]
ffba47a30f Update dependency ruby-vips to v2.3.0 (#37194)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 08:03:52 +00:00
David Roetzel
bb72ecd466 Add simple API to remove item from collection (#37225) 2025-12-15 08:03:49 +00:00
renovate[bot]
372de345d7 Update dependency sass to v1.96.0 (#37175)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 08:03:45 +00:00
David Roetzel
1766616ebc Refactor relation preloading (#37217) 2025-12-15 07:35:46 +00:00
Claire
d3afd087b5 Merge pull request #3314 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 4af8e83c8a
2025-12-13 00:55:28 +01:00
Claire
235af71f85 [Glitch] Fix wrapstodon not falling back to username when display name is not set
Port 4af8e83c8a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:59:53 +01:00
diondiondion
6734fd206e [Glitch] Change Emoji in Wrapstodon footer 🐘
Port 861202fd08 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:59:53 +01:00
diondiondion
cb1d1e289e [Glitch] Add secondary Wrapstodon share button
Port 6821b70796 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:59:53 +01:00
diondiondion
acf583d374 [Glitch] Remember revealed archetype on future Wrapstodon visits
Port b72b507584 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:59:53 +01:00
diondiondion
8fad8681ab [Glitch] Convert Settings class to TS
Port 8748f0812d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:59:53 +01:00
Echo
e7c383251b [Glitch] Wrapstodon: Add nav modal
Port e206b0d0de to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:59:52 +01:00
diondiondion
febd6241bf [Glitch] Change Wrapstodon 'About' link to point to joinmastodon.org
Port 571c93c563 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:48:32 +01:00
Echo
aa45a5fa83 [Glitch] Wrapstodon: Allow dismissing banner
Port 10f232ca08 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-12 17:48:12 +01:00
Claire
6503287c2d Merge commit '4af8e83c8a236265c46a1b984fa5dbd3a7c73dfe' into glitch-soc/merge-upstream 2025-12-12 17:45:26 +01:00
Claire
4af8e83c8a Fix wrapstodon not falling back to username when display name is not set (#37229) 2025-12-12 16:30:22 +00:00
diondiondion
861202fd08 Change Emoji in Wrapstodon footer 🐘 (#37226) 2025-12-12 14:31:21 +00:00
diondiondion
6821b70796 Add secondary Wrapstodon share button (#37224) 2025-12-12 13:39:56 +00:00
David Roetzel
3cc4b59b41 First draft of API to add items to a collection (#37222) 2025-12-12 13:09:55 +00:00
Claire
1e67567d8f Change HTTP Signature verification status from 401 to 503 on temporary failure to get remote actor (#37221) 2025-12-12 12:42:43 +00:00
diondiondion
b72b507584 Remember revealed archetype on future Wrapstodon visits (#37219) 2025-12-12 11:03:00 +00:00
diondiondion
8748f0812d Convert Settings class to TS (#37218) 2025-12-12 10:20:32 +00:00
Echo
e206b0d0de Wrapstodon: Add nav modal (#37210) 2025-12-12 10:11:47 +00:00
diondiondion
571c93c563 Change Wrapstodon 'About' link to point to joinmastodon.org (#37216) 2025-12-12 09:43:34 +00:00
Echo
10f232ca08 Wrapstodon: Allow dismissing banner (#37202) 2025-12-12 09:40:45 +00:00
Claire
88c0f52e99 Merge pull request #3313 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to d730f6b0c5
2025-12-11 19:23:18 +01:00
Claire
a56b739c68 [Glitch] Fix wrapstodon modal closing on any click
Port dfbf908870 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-11 19:07:26 +01:00
diondiondion
183a42a5ee [Glitch] Add Wrapstodon footer links
Port c06eb371e6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-11 19:06:54 +01:00
Claire
303a5478af Merge commit 'dfbf908870fcde76396ebccfb3d71ee1a06ffe82' into glitch-soc/merge-upstream
Conflicts:
- `app/views/wrapstodon/show.html.haml`:
  Conflict because of glitch-soc's theming system.
  Applied upstream's changes.
2025-12-11 19:05:32 +01:00
Claire
dfbf908870 Fix wrapstodon modal closing on any click (#37209) 2025-12-11 17:49:26 +00:00
diondiondion
aa067370d8 [Glitch] Fix Wrapstodon modal scrolling not working on iOS
Port 4323963053 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-11 18:07:59 +01:00
diondiondion
5e0db46b2a [Glitch] Wrapstodon design QA tweaks
Port 5651900b89 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-11 18:07:34 +01:00
diondiondion
c06eb371e6 Add Wrapstodon footer links (#37207) 2025-12-11 17:06:26 +00:00
Claire
53617cef5a Merge commit 'd730f6b0c5cfb18894d1a9e34d0aa2556dda3c62' into glitch-soc/merge-upstream 2025-12-11 18:05:28 +01:00
Emelia Smith
d730f6b0c5 Add spec for client_credentials being used with /api/v1/apps/verify_credentials (#37195) 2025-12-11 16:40:22 +00:00
Claire
addeb28292 Change wrapstodon 2025 to allow unlisted posts in top statuses (#37206) 2025-12-11 16:35:35 +00:00
Claire
5e3387539e Add image to Wrapstodon OpenGraph banner (#37205) 2025-12-11 16:22:48 +00:00
diondiondion
4323963053 Fix Wrapstodon modal scrolling not working on iOS (#37203) 2025-12-11 14:25:28 +00:00
diondiondion
5651900b89 Wrapstodon design QA tweaks (#37201) 2025-12-11 11:40:53 +00:00
renovate[bot]
d1b996b7e3 Update dependency omniauth-rails_csrf_protection to v2.0.1 (#37199)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 11:12:07 +00:00
renovate[bot]
fed26a41fa Update dependency jsdom to v27.3.0 (#37165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 10:33:47 +00:00
Claire
37d309bcaf Fix Wrapstodon font loading by disabling inlining of fonts in Vite (#37198) 2025-12-11 10:33:15 +00:00
renovate[bot]
d25f672c50 Update dependency active_model_serializers to v0.10.16 (#37167)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 10:07:52 +00:00
renovate[bot]
15c9088761 Update dependency vite to v7.2.7 (#37156)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 10:07:38 +00:00
renovate[bot]
da1505a495 Update dependency @vitejs/plugin-react to v5.1.2 (#37155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 10:07:30 +00:00
renovate[bot]
d1f690f50c Update dependency stoplight to v5.7.0 (#37151)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 10:07:25 +00:00
Claire
8b418b84d0 Merge pull request #3312 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to d6f2a3ac8d
2025-12-10 22:09:22 +01:00
diondiondion
f817300d8d [Glitch] Implement custom font for Wrapstodon heading
Port c42b9f6996 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-10 18:13:17 +01:00
Echo
35a89a0173 [Glitch] Fix issue where Wrapstodon was pushed to the bottom of the feed
Port 76184c998c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-10 18:12:23 +01:00
diondiondion
b5721dbd4a [Glitch] Fix Wrapstodon Storybook & other Wrapstodon issues
Port 8137ce87ce to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-10 18:11:08 +01:00
diondiondion
38f623eee7 [Glitch] Minor Wrapstodon tweaks, add stub Storybook page
Port 91500a7f53 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-10 18:09:09 +01:00
Claire
17ba99e5de Merge commit 'd6f2a3ac8d61e0828a17f68a6e9094d0f4662f4c' into glitch-soc/merge-upstream
Conflicts:
- `app/views/wrapstodon/show.html.haml`:
  Conflict because of glitch-soc's theming change.
  Adapted upstream's changes.
- `docker-compose.yml`:
  Conflict because of container repo name change.
  Adapted upstream's changes.
- `yarn.lock`:
  Conflict because of an additional glitch-soc dependency.
  Updated the dependencies upstream did.
2025-12-10 18:05:44 +01:00
Claire
da2b75bdcd Change build-releases workflow to tag images latest based on latest stable-x.y branch (#37179)
Co-authored-by: emilweth <7402764+emilweth@users.noreply.github.com>
2025-12-10 17:01:25 +00:00
David Roetzel
adf8a3601d Add service to add item to a collection (#37192) 2025-12-10 16:59:21 +00:00
Claire
d6f2a3ac8d Bump version to v4.5.3 (#37166) 2025-12-10 16:42:19 +00:00
diondiondion
c42b9f6996 Implement custom font for Wrapstodon heading (#37193) 2025-12-10 16:26:46 +00:00
Echo
76184c998c Fix issue where Wrapstodon was pushed to the bottom of the feed (#37190) 2025-12-10 15:55:12 +00:00
diondiondion
8137ce87ce Fix Wrapstodon Storybook & other Wrapstodon issues (#37189) 2025-12-10 14:07:25 +00:00
renovate[bot]
37426288d9 Update dependency postcss-preset-env to v10.5.0 (#37132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-10 12:53:39 +00:00
renovate[bot]
801fee7593 Update dependency test-prof to v1.5.0 (#37127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-10 12:53:29 +00:00
Claire
6838497fe8 Add title and description to Opengraph data for Wrapstodon share page (#37188) 2025-12-10 11:27:10 +00:00
Claire
7b8a5d42f1 Remove unused time series details from 2025 annual report (#37187) 2025-12-10 11:02:24 +00:00
Claire
cd71fdcdff Merge pull request #3311 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 9d81561bb2
2025-12-10 11:53:00 +01:00
diondiondion
91500a7f53 Minor Wrapstodon tweaks, add stub Storybook page (#37186) 2025-12-10 09:05:14 +00:00
Claire
5422e43e31 Fix wrapstodon standalone page not loading JS module 2025-12-10 09:49:09 +01:00
diondiondion
5a66331003 [Glitch] Update Wrapstodon design
Port 9d81561bb2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-09 18:27:14 +01:00
Matt Jankowski
09e3955145 [Glitch] Fix misc comment typos
Port ac71771d98 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-09 18:10:04 +01:00
Echo
e554e5723d [Glitch] Fix emoji on Wrapstodon
Port 9702cbb41c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-09 18:09:22 +01:00
Claire
315f5e5a31 Merge commit '9d81561bb2440c8fb9a75bd05277120aff346b1e' into glitch-soc/merge-upstream 2025-12-09 18:06:56 +01:00
diondiondion
9d81561bb2 Update Wrapstodon design (#37169) 2025-12-09 16:51:05 +00:00
Matt Jankowski
ac71771d98 Fix misc comment typos (#37183) 2025-12-09 16:09:01 +00:00
Claire
697569e5f9 Add account_id attribute to AnnualReport entity (#37182) 2025-12-09 15:59:40 +00:00
Claire
4cdcdaa7d9 Fix streaming image build after removal of .yarn (#37181) 2025-12-09 15:36:46 +00:00
Echo
9702cbb41c Fix emoji on Wrapstodon (#37177) 2025-12-09 10:36:08 +00:00
David Roetzel
ea768c17db Add counter cache to collections (#37176) 2025-12-09 10:31:35 +00:00
renovate[bot]
5347cabf3e Update dependency oj to v3.16.13 (#37135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 10:07:35 +00:00
renovate[bot]
eef40ba96b Update dependency hiredis-client to v0.26.2 (#37137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 09:47:12 +00:00
Matt Jankowski
9063c3b660 Remove yarn patch for babel-plugin-lodash, removed during Vite upgrade (#37161) 2025-12-09 09:30:57 +00:00
Matt Jankowski
e147947eb8 Add wrapstodon page spec (#37168) 2025-12-09 09:27:29 +00:00
Claire
8c52889c86 Merge pull request #3307 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 607449336d
2025-12-08 17:14:29 +01:00
Claire
05e45beb34 Merge commit '607449336da198ea9fe9c014220a5374a0ca1ae4' into glitch-soc/merge-upstream 2025-12-08 16:33:27 +01:00
Claire
607449336d Merge commit from fork 2025-12-08 15:44:08 +01:00
github-actions[bot]
85bf5be604 New Crowdin Translations (automated) (#37146)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-08 11:42:24 +00:00
David Roetzel
cf23f0414f Add id to collection serializers (#37157) 2025-12-08 11:40:17 +00:00
David Roetzel
55becaa1b5 Preload tag to prevent n+1 (#37154) 2025-12-08 10:30:10 +00:00
David Roetzel
8625721805 Draft API to get all collections by an account (#37139) 2025-12-08 08:56:13 +00:00
Claire
cd34331842 Merge pull request #3306 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 1ae3b4672b
2025-12-06 11:35:37 +01:00
Claire
691f4e3210 [Glitch] Fix “Delete and Redraft” on a non-quote being treated as a quote post in some cases
Port 1ae3b4672b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-05 20:08:05 +01:00
diondiondion
7f1862b67e [Glitch] Increase maximum height of media items on desktop
Port ce22c835ac to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-05 20:07:28 +01:00
Claire
71cda79e3b [Glitch] Remove more unused data from 2025 annual reports
Port 9b851616fe to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-05 20:06:12 +01:00
diondiondion
c3f254f170 [Glitch] Fix inversion of emoji colours based on dark/light mode
Port 591776d7ad to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-05 20:05:32 +01:00
Echo
05691293f0 [Glitch] Fixes YouTube embeds
Port 46f3b39fae to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-05 20:01:52 +01:00
Claire
2f6cdd6d47 Merge commit '1ae3b4672bffbc4aaf26f60c7063d6901239de5d' into glitch-soc/merge-upstream 2025-12-05 20:00:40 +01:00
Claire
4625bbe282 Merge pull request #3305 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstrema changes up to 65b216353e
2025-12-05 19:58:48 +01:00
diondiondion
4dc196b595 [Glitch] Handle dark/light/contrast theme modes in common CSS
Port 65b216353e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-05 19:29:37 +01:00
Claire
3b4c4c5b09 Merge commit '65b216353e9bc9ae8517d967f8c2cd8122551fdc' into glitch-soc/merge-upstream
- `app/helpers/application_helper.rb`:
  Upstream updated the classes used for theming purposes,
  but glitch-soc has its own theming system.
  Adapted upstream's changes.
- `spec/helpers/application_helper_spec.rb`:
  Upstream updated the classes used for theming purposes,
  but glitch-soc has its own theming system.
  Adapted upstream's changes.
2025-12-05 19:25:40 +01:00
Matt Jankowski
7fe3e80758 Rely on locale for options order in DOB input (#36895) 2025-12-05 15:21:22 +00:00
Claire
1ae3b4672b Fix “Delete and Redraft” on a non-quote being treated as a quote post in some cases (#37140) 2025-12-05 15:17:48 +00:00
Echo
007ae588d8 Fix incorrect date for Wrapstodon start (#37138) 2025-12-05 14:12:26 +00:00
diondiondion
ce22c835ac Increase maximum height of media items on desktop (#37136) 2025-12-05 13:39:48 +00:00
Claire
9b851616fe Remove more unused data from 2025 annual reports (#37134) 2025-12-05 13:36:37 +00:00
diondiondion
591776d7ad Fix inversion of emoji colours based on dark/light mode (#37120) 2025-12-05 10:08:59 +00:00
renovate[bot]
7f1f3236c6 Update opentelemetry-ruby (non-major) (#37101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:57:18 +00:00
renovate[bot]
852727a226 Update dependency aws-sdk-s3 to v1.206.0 (#37100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:57:02 +00:00
github-actions[bot]
429d6bcab4 New Crowdin Translations (automated) (#37131)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-05 09:43:12 +00:00
renovate[bot]
e47a5dd1c2 Update dependency faker to v3.5.3 (#37099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:22:32 +00:00
renovate[bot]
4ec761debd Update dependency sidekiq to v8.0.10 (#37090)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:20:54 +00:00
renovate[bot]
d895ea3433 Update dependency vite to v7.2.6 (#37076)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:20:45 +00:00
renovate[bot]
49105a28a3 Update eslint (non-major) (#36801)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:20:34 +00:00
renovate[bot]
1cb650d107 Update dependency jsdom to v27.2.0 (#36845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-05 09:20:17 +00:00
Claire
0f2ba97c99 Merge pull request #3304 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 0dac31dfd5
2025-12-04 21:42:55 +01:00
Echo
0061f9a699 [Glitch] Create new entrypoint for sharable Wrapstodon
Port 0dac31dfd5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 21:17:30 +01:00
Echo
2d93e63e43 [Glitch] Wrapstodon modal with new share button
Port 31c392b1bc to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 21:17:30 +01:00
diondiondion
5a5ba02f96 [Glitch] Fix color contrast issues caused by new theme tokens
Port 498e88f059 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 21:01:08 +01:00
Claire
c8f365fd1d Merge commit '0dac31dfd588e4cd866f382ed001a9535f06234a' into glitch-soc/merge-upstream 2025-12-04 20:59:54 +01:00
Claire
691fe7cb4c Merge pull request #3303 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to b3b5bf26d1
2025-12-04 20:58:43 +01:00
Echo
376332bfe7 [Glitch] Display Wrapstodon inline widget
Port e5e3a64a9b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:27:02 +01:00
Echo
8bec8c373b [Glitch] Remove noreferrer from external links
Port 234990cc37 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:25:52 +01:00
diondiondion
5f2d64c4b0 [Glitch] Add Wrapstodon timeline announcement component
Port 9aec6936e5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:21:09 +01:00
Echo
1faaa9706a [Glitch] Add UJS to buttons
Port 100b20f290 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:20:29 +01:00
Echo
ac926baa74 [Glitch] Emoji: Update emoji categories with featured emoji
Port c5c8100d02 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:20:06 +01:00
diondiondion
f21f8df4cc [Glitch] Ensure all pages have a solid background color
Port f5d6f60ca7 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:19:20 +01:00
Claire
62dc7c1ee6 [Glitch] Fix error handling when re-fetching already-known statuses
Port edfbcfb3f5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:18:59 +01:00
diondiondion
c63393c963 [Glitch] Don't reset scroll when using hotkeys to focus columns, add hotkey 0 to scroll to top
Port 9334bd9ede to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-12-04 20:18:28 +01:00
Claire
34aa825e96 Merge commit 'b3b5bf26d14f809a562244642949826b6a91bade' into glitch-soc/merge-upstream 2025-12-04 20:16:21 +01:00
Echo
46f3b39fae Fixes YouTube embeds (#37126) 2025-12-04 16:27:20 +00:00
diondiondion
65b216353e Handle dark/light/contrast theme modes in common CSS (#37095) 2025-12-04 15:56:35 +00:00
Echo
0dac31dfd5 Create new entrypoint for sharable Wrapstodon (#37121) 2025-12-04 15:48:10 +00:00
David Roetzel
75b9e9a8b0 Enable missing before actions in Collection API (#37122) 2025-12-04 15:35:47 +00:00
Claire
88aed3c11a Fix streamed quoted polls not being hydrated correctly (#37118) 2025-12-04 14:10:48 +00:00
David Roetzel
9921fa1af7 First draft API to delete collections (#37117) 2025-12-04 13:47:23 +00:00
David Roetzel
5a7a4fff11 First draft of Collection update API (#37110) 2025-12-04 10:00:21 +00:00
github-actions[bot]
9cf52fb976 New Crowdin Translations (automated) (#37115)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-04 09:19:08 +00:00
renovate[bot]
baef5b1659 Update dependency @optimize-lodash/rollup-plugin to v6 (#37062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-04 09:16:13 +00:00
Matt Jankowski
832d8c7397 Use thread support helper in concurrent insert tag spec (#37112) 2025-12-04 09:11:53 +00:00
Matt Jankowski
d063af2594 Add coverage for array vs string in Tag.find_or_create_by (#37113) 2025-12-04 08:46:24 +00:00
Echo
31c392b1bc Wrapstodon modal with new share button (#37109) 2025-12-03 16:25:36 +00:00
diondiondion
498e88f059 Fix color contrast issues caused by new theme tokens (#37105) 2025-12-03 15:43:26 +00:00
Matt Jankowski
7c730e9041 Use normalizes API for Tag display_name value (#35797) 2025-12-03 15:39:01 +00:00
Matt Jankowski
b3b5bf26d1 Remove duplicate set_locale around action in auth/registrations (#36455) 2025-12-03 15:34:10 +00:00
David Roetzel
4e6d1892b9 Fix creation of duplicate conversations (#37108) 2025-12-03 14:33:27 +00:00
Echo
e5e3a64a9b Display Wrapstodon inline widget (#37106) 2025-12-03 13:58:38 +00:00
Echo
234990cc37 Remove noreferrer from external links (#37107) 2025-12-03 13:54:58 +00:00
Claire
08da9d8fc5 Fix serialization of annual reports with share code (#37104) 2025-12-03 13:05:33 +00:00
Claire
c97d25fcbd Fix serialization of 2025 wrapstodon reports (#37103) 2025-12-03 12:53:16 +00:00
renovate[bot]
e222664539 Update DefinitelyTyped types (non-major) (#37073)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 11:17:01 +00:00
renovate[bot]
9d10137c7c Update dependency bundler-audit to v0.9.3 (#37061)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 11:15:47 +00:00
Claire
5d84957117 Add shareable wrapstodon links (#37047) 2025-12-03 11:00:41 +00:00
github-actions[bot]
954f397743 New Crowdin Translations (automated) (#37098)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-03 10:11:20 +00:00
Claire
73294e2561 Fix typo in AsyncRefresh ID for GenerateAnnualReportWorker (#37096) 2025-12-03 08:31:14 +00:00
Claire
d2e1c0e1e2 Merge pull request #3302 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 92278796c3
2025-12-02 22:18:31 +01:00
Claire
d600950b83 Remove unmaintained win95 theme 2025-12-02 21:06:16 +01:00
Claire
1ca3894048 Replace old glitch-soc themes by the new ones 2025-12-02 21:04:31 +01:00
Claire
13cf55c501 Merge commit '92278796c3d0fa43c08bd59f66815b196fb273a3' into glitch-soc/merge-upstream
Conflicts:
- `app/helpers/theme_helper.rb`:
  Upstream removed the feature flag and refactored, while we have a slightly
  different theming system.
  Updated accordingly.
- `stylelint.config.js`:
  Upstream removed overrides for the temporary themes.
  Did the same.
2025-12-02 20:45:10 +01:00
renovate[bot]
f393ff93cb Update dependency @optimize-lodash/rollup-plugin to v5.1.0 (#37039)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 13:45:33 +00:00
renovate[bot]
9c3b41f0a4 Update dependency vite-plugin-pwa to v1.2.0 (#37040)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 13:45:27 +00:00
renovate[bot]
e45ecc7d13 Update dependency express to v5.2.0 [SECURITY] (#37089)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 13:43:46 +00:00
Claire
f8422e1fa4 Add API for on-demand generation of annual reports (#37055) 2025-12-02 13:37:05 +00:00
diondiondion
9aec6936e5 Add Wrapstodon timeline announcement component (#37093) 2025-12-02 11:36:20 +00:00
Claire
2b25b65972 Add missing translations for web push notifications (#37078) 2025-12-02 10:52:08 +00:00
Echo
100b20f290 Add UJS to buttons (#37091) 2025-12-02 10:35:29 +00:00
Echo
c5c8100d02 Emoji: Update emoji categories with featured emoji (#37084) 2025-12-02 10:30:08 +00:00
github-actions[bot]
2e5744e8c6 New Crowdin Translations (automated) (#37088)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-02 10:20:40 +00:00
David Roetzel
2d203ca72a First draft of API to get a single collection (#37053) 2025-12-01 15:04:52 +00:00
Christian Oelschlegel
1f9ddb7cf6 fix(tag): prevent dupl. tags on concurrent inserts (#35792)
Co-authored-by: Christian Oelschlegel <oelschle@sciphy.de>
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2025-12-01 14:56:52 +00:00
Echo
048746e56b Hide domain for local emojis in admin (#37080) 2025-12-01 14:24:24 +00:00
diondiondion
f5d6f60ca7 Ensure all pages have a solid background color (#37081) 2025-12-01 14:16:27 +00:00
Claire
e5651e7e04 Make settings-related database migrations more robust (#37079) 2025-12-01 14:11:49 +00:00
Claire
edfbcfb3f5 Fix error handling when re-fetching already-known statuses (#37077) 2025-12-01 10:52:06 +00:00
github-actions[bot]
f562ad9f67 New Crowdin Translations (automated) (#37063)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-12-01 09:42:49 +00:00
Claire
a4357def8a Merge pull request #3301 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 37ccffa95a
2025-12-01 00:02:53 +01:00
diondiondion
bb097056dc [Glitch] Fix current item in pagination not highlighted with new theme tokens
Port 37ccffa95a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:52:13 +01:00
diondiondion
906dd88d7e [Glitch] Fix post navigation in single-column mode when Advanced UI is enabled
Port f12f198f61 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:51:49 +01:00
diondiondion
b3135c1eed [Glitch] Limit height of tall images in posts
Port 5f33ac208f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:51:21 +01:00
diondiondion
b1d00f288f [Glitch] Contain tall videos in full-width video container
Port 2bd7c855b0 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:50:56 +01:00
Claire
7bc48f2833 [Glitch] Fix filters not applying to search results
Port 44ff2c32d3 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:50:23 +01:00
Echo
9ede21cbe2 [Glitch] Fix media modal misalignment in Safari
Port f07cff42c2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:50:01 +01:00
Echo
17379b73f7 [Glitch] Replace Rails UJS library
Port 0d2e9522ff to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:48:45 +01:00
Claire
99ff59b7b2 Merge commit '37ccffa95a30772b55e3f18d486d699ee6c5f9e8' into glitch-soc/merge-upstream 2025-11-30 17:47:27 +01:00
diondiondion
51698213b5 [Glitch] Remove unused bundle-related Redux actions
Port 07ecf648dd to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:03:10 +01:00
diondiondion
78feddec79 [Glitch] Fix error page when logging out or boosting on mobile
Port e126cfc76d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:02:04 +01:00
diondiondion
9d47d6790f [Glitch] Fix null access error in card component
Port ee7e756e89 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:01:23 +01:00
diondiondion
3b4b57e950 [Glitch] Refactor Card component to TypeScript
Port f87f30c1ac to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 17:00:53 +01:00
diondiondion
b75a01634e [Glitch] Fix issues in new theme tokens
Port 59e48657cf to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 16:51:16 +01:00
diondiondion
18d46054b5 [Glitch] Replace most unsafe React lifecycle methods
Port 8c772028ac to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 16:50:13 +01:00
diondiondion
281d12d5d6 [Glitch] Prevent vertical videos from overflowing the viewport
Port 861625fdca to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-30 16:41:33 +01:00
Claire
44e6abe48b Merge commit '0004ed4c8021ebd400d32eb32a5e479ebd7bcf91' into glitch-soc/merge-upstream 2025-11-30 16:40:18 +01:00
Claire
2e543ff246 Port new refactored themes to glitch-soc (#3296) 2025-11-30 16:37:40 +01:00
diondiondion
9334bd9ede Don't reset scroll when using hotkeys to focus columns, add hotkey 0 to scroll to top (#37052) 2025-11-28 16:19:23 +00:00
Claire
801672e3cb Add method to quickly test for AnnualReport account eligibility (#37045) 2025-11-28 16:19:23 +00:00
diondiondion
92278796c3 Remove theme_tokens feature flag & make new styles the default (#37056) 2025-11-28 15:58:46 +00:00
diondiondion
37ccffa95a Fix current item in pagination not highlighted with new theme tokens (#37054) 2025-11-28 14:45:38 +00:00
Echo
84ffb107c3 Adjust Chromatic to run conditionally (#37050) 2025-11-28 13:37:04 +00:00
David Roetzel
f896bbac3b Draft API to create Collections (#37049) 2025-11-28 13:30:43 +00:00
github-actions[bot]
6b38352b17 New Crowdin Translations (automated) (#37042)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-28 10:44:50 +00:00
diondiondion
f12f198f61 Fix post navigation in single-column mode when Advanced UI is enabled (#37044) 2025-11-28 10:05:54 +00:00
Claire
e0912c1729 Fix Card component using incorrect punycode module (#37043) 2025-11-28 09:50:37 +00:00
Claire
945ef5a8e1 Remove unused data from 2025 annual reports (#37033) 2025-11-28 08:58:34 +00:00
diondiondion
5f33ac208f Limit height of tall images in posts (#37035) 2025-11-27 17:05:56 +00:00
diondiondion
2bd7c855b0 Contain tall videos in full-width video container (#37032) 2025-11-27 17:05:21 +00:00
Claire
44ff2c32d3 Fix filters not applying to search results (#36346) 2025-11-27 16:23:11 +00:00
Eashwar Ranganathan
826e9d7047 Make tootctl aware of 'require approval' for email domains (#34579) 2025-11-27 15:52:59 +00:00
Echo
f07cff42c2 Fix media modal misalignment in Safari (#37034) 2025-11-27 15:27:18 +00:00
Echo
0d2e9522ff Replace Rails UJS library (#37031) 2025-11-27 13:10:55 +00:00
renovate[bot]
0004ed4c80 chore(deps): update opentelemetry-ruby (non-major) (#37016)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 10:51:57 +00:00
diondiondion
07ecf648dd Remove unused bundle-related Redux actions (#37030) 2025-11-27 10:50:48 +00:00
github-actions[bot]
90466d0262 New Crowdin Translations (automated) (#37026)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-27 09:51:15 +00:00
Matt Jankowski
199376a080 Use existing time format string to generate backup archive filename (#36469) 2025-11-27 09:38:27 +00:00
diondiondion
e126cfc76d Fix error page when logging out or boosting on mobile (#37028) 2025-11-27 09:36:58 +00:00
David Roetzel
322a4fee53 First steps towards a collection creation service (#37020)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2025-11-27 09:36:44 +00:00
renovate[bot]
be2caba527 chore(deps): update dependency i18n-tasks to v1.1.2 (#37027)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 09:29:14 +00:00
renovate[bot]
002632c3bb chore(deps): update dependency aws-sdk-core to v3.239.2 (#37015)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 16:18:51 +00:00
renovate[bot]
81510455d1 chore(deps): update yarn to v4.12.0 (#36797)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 16:18:48 +00:00
diondiondion
ee7e756e89 Fix null access error in card component (#37022) 2025-11-26 14:55:40 +00:00
diondiondion
f87f30c1ac Refactor Card component to TypeScript (#36982) 2025-11-26 12:56:17 +00:00
renovate[bot]
1757a0f0f3 chore(deps): update dependency public_suffix to v7 (#36920)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 10:48:12 +00:00
Matt Jankowski
cb4f1cc89c Improve SessionActivation.activate spec (#36983) 2025-11-26 10:26:39 +00:00
Claire
00163e89bf Fix tootctl status remove removing quoted posts and remote quotes of local posts (#37009) 2025-11-26 10:26:26 +00:00
diondiondion
59e48657cf Fix issues in new theme tokens (#37019) 2025-11-26 10:25:49 +00:00
github-actions[bot]
384594f462 New Crowdin Translations (automated) (#37018)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-26 10:25:41 +00:00
renovate[bot]
cd9d166312 chore(deps): update dependency rqrcode to v3.1.1 (#37010)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 09:54:11 +00:00
renovate[bot]
6f4f9942b9 chore(deps): update dependency connection_pool to v2.5.5 (#37003)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 09:53:38 +00:00
Claire
7e7c21032b Merge pull request #3300 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to ca53195b31
2025-11-25 18:48:10 +01:00
Claire
382dec843b [Glitch] Fix compose autosuggest always lowercasing token
Port a26636ff1f to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-25 18:23:34 +01:00
Claire
868d45df2f Merge commit 'ca53195b31ef7eb9205f879e022b09b28efc9314' into glitch-soc/merge-upstream 2025-11-25 18:22:48 +01:00
David Roetzel
0725afe1a9 Collections: Add missing validations for boolean columns (#37005) 2025-11-25 14:46:50 +00:00
renovate[bot]
09697045a9 chore(deps): update dependency rails-i18n to v8.1.0 (#36992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 14:18:48 +00:00
renovate[bot]
3e77c3bc8c chore(deps): update dependency omniauth-rails_csrf_protection to v2 (#36993)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 14:18:32 +00:00
renovate[bot]
bd02cd4591 chore(deps): update dependency addressable to v2.8.8 (#37002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 14:07:06 +00:00
renovate[bot]
4ca458e0b4 chore(deps): update devdependencies (non-major) (#36802)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 13:53:23 +00:00
diondiondion
8c772028ac Replace most unsafe React lifecycle methods (#36970) 2025-11-25 13:49:45 +00:00
diondiondion
861625fdca Prevent vertical videos from overflowing the viewport (#36966) 2025-11-25 13:21:59 +00:00
renovate[bot]
ca53195b31 chore(deps): update dependency sass to v1.94.2 (#36826)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-25 13:21:25 +00:00
Claire
a26636ff1f Fix compose autosuggest always lowercasing token (#36995) 2025-11-25 13:17:44 +00:00
Claire
204143becc Increase HTTP read timeout for expensive S3 batch delete operation (#37004) 2025-11-25 10:18:34 +00:00
github-actions[bot]
f0d7ea61ef New Crowdin Translations (automated) (#37000)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-25 09:52:51 +00:00
Claire
4d92051f40 Merge pull request #3299 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 76d8ac3fe6
2025-11-24 19:26:06 +01:00
Claire
b76530a7f1 Merge commit '76d8ac3fe680e92d20059c590ccb1cd8f74078c2' into glitch-soc/merge-upstream 2025-11-24 19:08:03 +01:00
renovate[bot]
76d8ac3fe6 chore(deps): update dependency i18n-tasks to v1.1.1 (#36997)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-24 15:34:10 +00:00
Claire
96d5e57351 Revert "Increase HTTP read timeout for expensive S3 batch delete operation (#36971)" (#36996) 2025-11-24 13:33:37 +00:00
renovate[bot]
57bfe863f3 chore(deps): update dependency aws-sdk-core to v3.239.1 (#36955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-24 09:10:07 +00:00
David Roetzel
b16452dd99 Add shared context for API authentication (#36981) 2025-11-24 08:48:49 +00:00
renovate[bot]
1bc13609ab chore(deps): update dependency aws-sdk-s3 to v1.205.0 (#36956)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-24 08:42:56 +00:00
github-actions[bot]
e44a9c0879 New Crowdin Translations (automated) (#36984)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-24 08:08:01 +00:00
Matt Jankowski
f1bf6e6344 Remove unused from_limited? method from NotifyService (#36988) 2025-11-24 07:57:46 +00:00
Claire
5885b6715a Merge pull request #3295 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 585545d0d5
2025-11-21 23:09:23 +01:00
diondiondion
975c7097b8 [Glitch] Refactor PrivacyDropdown to TypeScript
Port 8a235dd187 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-21 19:35:20 +01:00
Claire
652ed7ab50 Merge commit '585545d0d5678a6ea4b958af4a3bc6593134d0f6' into glitch-soc/merge-upstream 2025-11-21 19:33:14 +01:00
Matt Jankowski
585545d0d5 Add coverage for media#player scenarios (#35947) 2025-11-21 14:46:29 +00:00
Matt Jankowski
d967137adf Remove unneeded type check on Status in og_image partial (#36980) 2025-11-21 14:29:03 +00:00
Pēteris Caune
ad7839e551 Fix the translation of "Latvian" (#36876) 2025-11-21 13:56:20 +00:00
diondiondion
8a235dd187 Refactor PrivacyDropdown to TypeScript (#36979) 2025-11-21 13:33:27 +00:00
Shugo Maeda
48fe679728 Separate remote thumbnails into cache/ directory (#36911) 2025-11-21 13:27:04 +00:00
renovate[bot]
687f3a2a01 chore(deps): update dependency vite to v7.2.4 (#36964)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-21 11:00:29 +00:00
David Roetzel
7ffa5fa0c4 Add models to represent "Collections" (#36977) 2025-11-21 10:28:23 +00:00
github-actions[bot]
cfa4f402ef New Crowdin Translations (automated) (#36976)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-21 09:34:55 +00:00
renovate[bot]
aa131e538c chore(deps): update dependency core-js to v3.47.0 (#36931)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-21 09:17:57 +00:00
Matt Jankowski
6151febd73 Suggest ES image version 7.17.29 in docker compose (#36972) 2025-11-21 09:16:50 +00:00
Claire
a54334b714 Increase HTTP read timeout for expensive S3 batch delete operation (#36971) 2025-11-21 08:59:07 +00:00
Claire
2f2065751d Merge pull request #3294 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 21ce99f746
2025-11-20 22:44:55 +01:00
diondiondion
aec23fd4a2 [Glitch] Fix error when visiting non-public hashtag timelines
Port f01e80bed3 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-20 18:20:53 +01:00
Darius Kazemi
8e70c54d0e [Glitch] Remove stray Font Awesome styles
Port dc67dbba82 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-20 18:19:33 +01:00
Claire
284223f45f [Glitch] Fix statuses without text disappearing on reload
Port bb9a633b99 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-20 18:19:11 +01:00
Echo
8e68d6c6bf [Glitch] Improve media modal swipe animation
Port ea616ac4a4 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-20 18:18:46 +01:00
Claire
dd7d750f5d Merge commit '21ce99f746e17867df74029d3b2caca45588818d' into glitch-soc/merge-upstream 2025-11-20 18:13:37 +01:00
Claire
21ce99f746 Bump version to v4.5.2 (#36968) 2025-11-20 15:04:22 +00:00
github-actions[bot]
8e8669b5ef New Crowdin Translations (automated) (#36957)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-20 10:54:39 +00:00
Claire
a28f1d0110 Fix missing fallback link in CW-only quote posts (#36963) 2025-11-20 10:08:36 +00:00
diondiondion
f01e80bed3 Fix error when visiting non-public hashtag timelines (#36961) 2025-11-20 10:08:00 +00:00
Darius Kazemi
dc67dbba82 Remove stray Font Awesome styles (#36960) 2025-11-20 10:02:50 +00:00
Claire
bb9a633b99 Fix statuses without text disappearing on reload (#36962) 2025-11-20 09:52:53 +00:00
Claire
21110f0270 Fix d bookmark keyboard shortcut (#3285) 2025-11-19 22:25:53 +01:00
Claire
4612014192 Merge pull request #3288 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 366856f3bc
2025-11-19 22:25:28 +01:00
diondiondion
b1974a2147 [Glitch] Fix g + h keyboard shortcut not working when a post is focused
Port 4d0aab4a31 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:07:22 +01:00
Claire
c57ca36006 [Glitch] Fix quoting overwriting current content warning
Port c22b203bca to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:07:22 +01:00
Claire
69dfde3153 [Glitch] Fix scroll-to-status in threaded view being unreliable
Port be0e23bb0a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 22:07:22 +01:00
Claire
c5a6519af9 [Glitch] Change private quote education modal to not show up on self-quotes
Port c820c66d3c to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 21:54:24 +01:00
Claire
9c7f27ba14 [Glitch] Fix double encoding in links
Port b4daad8c89 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 21:51:54 +01:00
Echo
76ba4000d9 [Glitch] Emoji: Fix path resolution for emoji worker
Port caffb0fd63 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 21:51:34 +01:00
diondiondion
89d04f3bb3 [Glitch] Fix superfluous border & spacing in domains list on the Moderation > Federation page
Port 72c582e7e5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-19 21:50:37 +01:00
Claire
7a56972381 Merge commit '366856f3bcdc2ff008b04e493a5de317ab83d5d0' into glitch-soc/merge-upstream 2025-11-19 21:49:09 +01:00
Claire
a4fd9b704a Merge commit '284b46fee7ad682b52c99d0455a1134e1d4e3fc3' into glitch-soc/merge-upstream
Conflicts:
- `app/helpers/theme_helper.rb`:
  Upstream added an experimental feature flag to try out theme refactors.
  Glitch-soc's theming system is too different, so skips the new feature flag.
- `stylelint.config.js`:
  Ditto.
2025-11-19 21:34:53 +01:00
Claire
fa721568e0 Change quotes to inherit local-only status of quoted post in composer (#3286) 2025-11-19 21:28:51 +01:00
Echo
ea616ac4a4 Improve media modal swipe animation (#36916) 2025-11-19 15:56:24 +00:00
renovate[bot]
01b11c328c chore(deps): update dependency i18n-tasks to v1.1.0 (#36907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-19 15:37:02 +00:00
Claire
bc7c83ba76 Update glob dependency (#36940) 2025-11-19 15:28:57 +00:00
diondiondion
366856f3bc Fix theme-related Vite errors even when theme_tokens feature flag is disabled (#36936) 2025-11-19 12:37:15 +00:00
diondiondion
4d0aab4a31 Fix g + h keyboard shortcut not working when a post is focused (#36935) 2025-11-19 10:58:07 +00:00
Claire
c22b203bca Fix quoting overwriting current content warning (#36934) 2025-11-19 10:35:10 +00:00
renovate[bot]
52b92bdc9c chore(deps): update dependency bootsnap to '~> 1.19.0' (#36906)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-19 10:19:49 +00:00
Matt Jankowski
4f6a7e44d1 Update rubocop-rspec to version 3.8.0 (#36853) 2025-11-19 10:14:51 +00:00
github-actions[bot]
81ffd1d3c7 New Crowdin Translations (automated) (#36933)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-19 10:09:54 +00:00
Matt Jankowski
9872197d1f Fix Rails/RedirectBackOrTo cop (#36930) 2025-11-19 09:28:43 +00:00
Claire
41279ac801 Fix threaded mode not resetting quote (#3284) 2025-11-18 18:38:53 +01:00
Claire
902b5a169c Clean up CSS differences with upstream (#3283) 2025-11-18 18:38:48 +01:00
Claire
be0e23bb0a Fix scroll-to-status in threaded view being unreliable (#36927) 2025-11-18 16:20:50 +00:00
Claire
c820c66d3c Change private quote education modal to not show up on self-quotes (#36926) 2025-11-18 16:17:26 +00:00
Claire
b4daad8c89 Fix double encoding in links (#36925) 2025-11-18 15:37:14 +00:00
github-actions[bot]
b14f113929 New Crowdin Translations (automated) (#36922)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-18 08:22:25 +00:00
Echo
caffb0fd63 Emoji: Fix path resolution for emoji worker (#36897) 2025-11-17 15:34:18 +00:00
Matt Jankowski
53703202fb Add IpBlock#to_cidr method to build string (#35773) 2025-11-17 14:51:05 +00:00
Matt Jankowski
59fdff5dc5 Add spec for translation attempt with ineligible target language (#36813) 2025-11-17 14:13:52 +00:00
renovate[bot]
04bdfa1957 chore(deps): update dependency @vitejs/plugin-react to v5.1.1 (#36841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-17 14:12:38 +00:00
Shugo Maeda
04c566e2e9 Fix ArgumentError of tootctl upgrade storage-schema (#36914) 2025-11-17 13:34:20 +00:00
diondiondion
72c582e7e5 Fix superfluous border & spacing in domains list on the Moderation > Federation page (#36915) 2025-11-17 12:07:44 +00:00
diondiondion
284b46fee7 Implement CSS theme tokens behind feature flag (#36861) 2025-11-17 09:44:55 +00:00
github-actions[bot]
489bee8f4e New Crowdin Translations (automated) (#36898)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-17 09:33:15 +00:00
Claire
932f479a34 Fix missing alt-text confirmation modal not opening (#3281) 2025-11-15 12:03:56 +01:00
Claire
8839ecf2a4 Merge pull request #3279 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to c87b052829
2025-11-15 11:18:59 +01:00
Claire
5645a017b3 [Glitch] Fix inability to paste links
Port c87b052829 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:29:07 +01:00
Echo
8817ebda50 [Glitch] Remove rails delegate
Port 7dbb2ac79a to glitch-soc

Co-authored-by: Renaud Chaput <renchap@gmail.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:28:42 +01:00
Jeong Arm
f782c2c8e9 [Glitch] Allow drag&drop of link to quote in compose form
Port 4ab1d5d724 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:27:29 +01:00
Echo
ee257dc307 [Glitch] Fix error with remote tags including percent signs
Port c5eca8ffb2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:26:42 +01:00
Claire
8240644b6e [Glitch] Fix bogus quote approval policy not always being replaced correctly
Port f25e066112 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:25:37 +01:00
Claire
593d21d2ed [Glitch] Fix hashtag completion not being inserted correctly
Port 6d8c43ab85 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:24:45 +01:00
diondiondion
951816c5d6 [Glitch] Fix Cmd/Ctrl + Enter in the composer triggering confirmation dialog action
Port 6e294828d6 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-14 18:24:22 +01:00
Claire
e0d7230f97 Merge commit 'c87b05282909383353a9561e97b9f18a2db0766d' into glitch-soc/merge-upstream 2025-11-14 18:19:00 +01:00
Claire
c87b052829 Fix inability to paste links (#36896) 2025-11-14 16:44:08 +00:00
github-actions[bot]
ebc99cd597 New Crowdin Translations (automated) (#36893)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-14 15:57:35 +00:00
Claire
6db4297193 Fix cross-origin handling of CSS modules (#36890) 2025-11-14 15:42:26 +00:00
renovate[bot]
bc47cba123 chore(deps): update dependency js-yaml to v4.1.1 [security] (#36891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 15:27:43 +00:00
Matt Jankowski
f8ffb85566 Use date attribute for date of birth (#36039) 2025-11-14 15:17:53 +00:00
Echo
7dbb2ac79a Remove rails delegate (#36835)
Co-authored-by: Renaud Chaput <renchap@gmail.com>
2025-11-14 14:18:14 +00:00
renovate[bot]
bc81e299f2 chore(deps): update dependency stoplight to v5.6.0 (#36803)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 14:17:50 +00:00
renovate[bot]
277a4c80c0 chore(deps): update dependency prometheus_exporter to v2.3.1 (#36842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 14:17:38 +00:00
renovate[bot]
7be8fe6370 chore(deps): update dependency aws-sdk-core to v3.237.0 (#36823)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 14:15:56 +00:00
Jeong Arm
4ab1d5d724 Allow drag&drop of link to quote in compose form (#36859) 2025-11-14 14:14:37 +00:00
Echo
c5eca8ffb2 Fix error with remote tags including percent signs (#36886) 2025-11-14 14:11:41 +00:00
Claire
f25e066112 Fix bogus quote approval policy not always being replaced correctly (#36885) 2025-11-14 12:39:04 +00:00
Claire
6d8c43ab85 Fix hashtag completion not being inserted correctly (#36884) 2025-11-14 12:23:40 +00:00
Claire
0d7c23469b Bump version to v4.5.1 (#36872) 2025-11-14 10:43:08 +00:00
github-actions[bot]
f243a00b90 New Crowdin Translations (automated) (#36875)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-14 10:27:20 +00:00
diondiondion
6e294828d6 Fix Cmd/Ctrl + Enter in the composer triggering confirmation dialog action (#36870) 2025-11-14 09:39:42 +00:00
Claire
101bd01e6e Merge pull request #3277 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 98c8c1ebd2
2025-11-13 18:40:45 +01:00
Claire
d53ff25529 [Glitch] Fix error when sending new posts
Port 98c8c1ebd2 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 18:14:59 +01:00
Claire
8ab9040afc [Glitch] Fix posts coming from public/hashtag streaming being marked as unquotable
Port 9dbebbb2ee to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 18:14:42 +01:00
diondiondion
19cc39abf0 [Glitch] Fix Cmd/Ctrl + Enter not submitting Alt text modal on some browsers
Port 998d4cc0dc to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-13 18:14:27 +01:00
Claire
bebc79d160 Merge commit '98c8c1ebd278f59e97c7d17628e7710cd4c933d4' into glitch-soc/merge-upstream 2025-11-13 18:12:49 +01:00
Claire
98c8c1ebd2 Fix error when sending new posts (#36869) 2025-11-13 15:42:14 +00:00
diondiondion
998d4cc0dc Fix Cmd/Ctrl + Enter not submitting Alt text modal on some browsers (#36866) 2025-11-13 15:35:25 +00:00
Claire
9dbebbb2ee Fix posts coming from public/hashtag streaming being marked as unquotable (#36860) 2025-11-13 12:54:28 +00:00
github-actions[bot]
3f292e0f5b New Crowdin Translations (automated) (#36858)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-13 10:18:16 +00:00
Claire
9dd7c816d2 Merge pull request #3275 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 7e7f63a2ef
2025-11-12 19:35:15 +01:00
Claire
191d6b071c [Glitch] Revert "Ensure the boost button shows a numeric value (#36805)"
Port 8abec0ffcb to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-12 18:15:19 +01:00
Echo
5f01e75290 [Glitch] Fix deprecation warning in Vite
Port 00cbc1b910 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-12 18:14:54 +01:00
diondiondion
1c749e21f8 [Glitch] Fixes blank screen in browsers that don't support Intl.DisplayNames
Port f303f3458d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-12 18:14:11 +01:00
Claire
01f9397e37 [Glitch] Fix filters not being applied to quotes in detailed view
Port 9f3573d446 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-12 18:13:49 +01:00
Echo
62ce66dacb [Glitch] Fix duplicate counters
Port 4b1532e008 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-12 18:13:27 +01:00
Claire
9525134c28 Merge commit '7e7f63a2efc83edd7c59a12e55eaab9509a4c15b' into glitch-soc/merge-upstream 2025-11-12 18:11:41 +01:00
Itoh Shimon
7e7f63a2ef Use the native script for Divehi (#36254) 2025-11-12 16:58:40 +00:00
Claire
ed3710e58f Fix Update importing old previously-unknown activities and treating them as recent ones (#36848) 2025-11-12 16:09:00 +00:00
Claire
8abec0ffcb Revert "Ensure the boost button shows a numeric value (#36805)" (#36850) 2025-11-12 15:32:55 +00:00
Echo
00cbc1b910 Fix deprecation warning in Vite (#36849) 2025-11-12 14:25:25 +00:00
diondiondion
f303f3458d Fixes blank screen in browsers that don't support Intl.DisplayNames (#36847) 2025-11-12 11:11:48 +00:00
Claire
9f3573d446 Fix filters not being applied to quotes in detailed view (#36843) 2025-11-12 11:09:51 +00:00
Echo
4b1532e008 Fix duplicate counters (#36844) 2025-11-12 11:01:34 +00:00
github-actions[bot]
ff0fca018a New Crowdin Translations (automated) (#36838)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-12 10:24:50 +00:00
Claire
12ac3317aa Merge pull request #3273 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to b5a2fe715d
2025-11-12 09:49:33 +01:00
diondiondion
fdfbc63199 [Glitch] Fix icon buttons animating when they haven't changed
Port b53ee04475 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-11 20:25:33 +01:00
Echo
e265c6bd4c [Glitch] Emoji: Load emoji with hash in URL
Port ff5d745e3d to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-11 20:25:14 +01:00
Claire
48146e5371 Merge commit 'b5a2fe715d158d5fdf4ad9ddef0787b781b4da6e' into glitch-soc/merge-upstream 2025-11-11 20:22:04 +01:00
Echo
b5a2fe715d Revert "Fix duplicated counters (fix #32614)" (#36834) 2025-11-11 18:05:44 +00:00
renovate[bot]
11b75d616a chore(deps): update dependency aws-sdk-s3 to v1.203.1 (#36822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 15:47:08 +00:00
Asahi Lina
394ed551bb Serialize legacy quotes (#3203) 2025-11-11 13:23:51 +01:00
Claire
565f437f93 Merge pull request #3230 from glitch-soc/i18n/crowdin/translations
New Crowdin Translations (automated)
2025-11-11 12:51:18 +01:00
Matt Jankowski
a002048c8c Update storybook/msw/chromatic (#36739) 2025-11-11 11:17:23 +00:00
Matt Jankowski
fa5318b333 Remove webpack hints IDE config (#36769) 2025-11-11 11:16:15 +00:00
Claire
095a9571e2 Update simple_form.no.yml 2025-11-11 12:15:55 +01:00
Claire
7ca2a7d9d6 Update no.yml 2025-11-11 12:15:43 +01:00
diondiondion
b53ee04475 Fix icon buttons animating when they haven't changed (#36824) 2025-11-11 11:10:27 +00:00
Claire
2759bafe09 Merge pull request #3272 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 1c3e7545cb
2025-11-11 12:07:29 +01:00
xatier
84cdb6cc66 Fix duplicated counters (fix #32614) (#36785) 2025-11-11 11:02:41 +00:00
Echo
ff5d745e3d Emoji: Load emoji with hash in URL (#36808) 2025-11-11 10:03:06 +00:00
github-actions[bot]
391c77f277 New Crowdin Translations (automated) (#36820)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-11 08:38:02 +00:00
Renaud Chaput
bc5397a0db Remove the 2 PRs-per-hour Renovate limit (#36814) 2025-11-11 08:26:43 +00:00
Echo
f5cbe73d76 [Glitch] Centers GIFs in media modal
Port 4ddddc2573 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-10 23:04:50 +01:00
diondiondion
5af57000a0 [Glitch] Fix scroll shift caused by fetch-all-replies alerts
Port 400943cb4e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-10 22:30:53 +01:00
Echo
c428129c48 [Glitch] Ensure the boost button shows a numeric value
Port 9a42d00c12 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-10 22:30:26 +01:00
Renaud Chaput
5b75667c03 [Glitch] Update to latest eslint-plugin-react-hooks
Port 9addad8ce5 to glitch-soc

Co-authored-by: diondiondion <mail@diondiondion.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-10 22:29:58 +01:00
diondiondion
01f7a6796f [Glitch] Fix dropdown menu not focusing first item when opened via keyboard
Port 1280792678 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-10 22:22:49 +01:00
Claire
d31aaf9ed8 Merge commit '1c3e7545cb6137025a6efd208d195352c54ffda8' into glitch-soc/merge-upstream 2025-11-10 22:18:01 +01:00
Matt Jankowski
1c3e7545cb Add spec for translation attempt on private status (#36810) 2025-11-10 16:05:20 +00:00
diondiondion
400943cb4e Fix scroll shift caused by fetch-all-replies alerts (#36807) 2025-11-10 15:33:56 +00:00
Echo
9a42d00c12 Ensure the boost button shows a numeric value (#36805) 2025-11-10 15:10:24 +00:00
Renaud Chaput
9addad8ce5 Update to latest eslint-plugin-react-hooks (#36702)
Co-authored-by: diondiondion <mail@diondiondion.com>
2025-11-10 14:50:04 +00:00
Echo
4ddddc2573 Centers GIFs in media modal (#36806) 2025-11-10 13:21:45 +00:00
diondiondion
1280792678 Fix dropdown menu not focusing first item when opened via keyboard (#36804) 2025-11-10 11:44:10 +00:00
Matt Jankowski
63e2ca5d27 Add spec for hitting max status pins limit in pin api (#36789) 2025-11-10 10:06:47 +00:00
github-actions[bot]
b0790d828c New Crowdin Translations (automated) (#36786)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-10 10:06:07 +00:00
renovate[bot]
89b5ceb5dc chore(deps): update dependency vite to v7.2.2 (#36751)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 09:03:33 +00:00
GitHub Actions
91d17b5891 New Crowdin translations 2025-11-09 04:34:42 +00:00
Claire
6153479bad Merge pull request #3271 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 441eb89537
2025-11-08 18:19:16 +01:00
Echo
474cab03bd [Glitch] Reset background color on media modal
Port 882afd7748 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-08 10:46:33 +01:00
Claire
08ef682995 [Glitch] Fix prepared quote not being discarded with contents when replying
Port 315833cb75 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-08 10:46:14 +01:00
Claire
c1ef6e31cb Merge commit '441eb895371cf8ed6a5b8e294367bbbfd0f4c037' into glitch-soc/merge-upstream 2025-11-08 10:44:43 +01:00
renovate[bot]
441eb89537 chore(deps): update dependency axios to v1.13.2 (#36726)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 13:25:41 +00:00
Echo
882afd7748 Reset background color on media modal (#36782) 2025-11-07 10:44:31 +00:00
Claire
8fb06ea0ca Update dependency rollup from 4.46.2 to 4.46.4 (#36781) 2025-11-07 10:29:05 +00:00
Matt Jankowski
c7dc5767d3 Rely on puma default environment setting (#36760) 2025-11-07 10:06:22 +00:00
Matt Jankowski
6833878f95 Clarify hint for bootstrap account instructions (#36771) 2025-11-07 10:05:52 +00:00
Claire
70d71c10c8 Fix /api/v1/statuses/:id/context sometimes returing Mastodon-Async-Refresh without result_count (#36779) 2025-11-07 10:02:25 +00:00
Claire
315833cb75 Fix prepared quote not being discarded with contents when replying (#36778) 2025-11-07 09:11:10 +00:00
github-actions[bot]
dcf7fc1028 New Crowdin Translations (automated) (#36777)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-07 08:34:18 +00:00
Claire
0ace564537 Add 4.5.x to the list of supported branches (#36762) 2025-11-06 16:23:56 +00:00
Matt Jankowski
16dfa32578 Update express to version 5.1.0 (#36669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 14:46:08 +00:00
Matt Jankowski
0d48005b8a Remove legacy AR connection boot from puma config (#36757) 2025-11-06 14:36:23 +00:00
renovate[bot]
59e0ead418 chore(deps): update dependency stoplight to v5.5.0 (#36731)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 14:24:43 +00:00
renovate[bot]
76fb15dced chore(deps): update dependency aws-sdk-s3 to v1.203.0 (#36746)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 14:17:04 +00:00
Claire
4d44f4c57e Merge pull request #3270 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 6f1a30c4a6
2025-11-06 15:15:19 +01:00
renovate[bot]
5d3c1cdc9b chore(deps): update libretranslate/libretranslate docker tag to v1.7.3 (#36724)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 14:03:35 +00:00
github-actions[bot]
15c33a16f7 New Crowdin Translations (automated) (#36749)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-06 13:55:37 +00:00
Claire
152505dd9e Merge commit '6f1a30c4a6ea49ff7935f19f5a2cefab3eee9e7c' into glitch-soc/merge-upstream 2025-11-06 14:43:18 +01:00
Claire
6f1a30c4a6 Bump version to v4.5.0 (#36754) 2025-11-06 13:24:58 +00:00
Claire
1a890d2077 Merge pull request #3268 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 58b3fc0379
2025-11-06 13:09:22 +01:00
diondiondion
c8ebc974d1 [Glitch] Refactor "New/Edit list" page to avoid setting state in effect
Port 58b3fc0379 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:44:11 +01:00
Echo
53780dd49e [Glitch] Fix: correctly dismisses announcement when viewed
Port 41a4022988 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:43:47 +01:00
Echo
663f93ca6a [Glitch] Add default visualizer for audio upload without poster
Port 987104f435 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:43:23 +01:00
Echo
13395e2d4d [Glitch] Add new ESLint rule requiring explicit button types
Port 6337e036f3 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:42:17 +01:00
diondiondion
e1b7da0985 [Glitch] Fix spoiler toggle button being able to submit compose form
Port 1b8d1cd6e4 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:37:39 +01:00
diondiondion
ce080a1ca8 [Glitch] Add some outer page spacing when viewport width equals content width
Port 947dfcc548 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-06 12:37:17 +01:00
Claire
58b29be439 Merge commit '58b3fc03796dbde54dbba9a4c554c2d8d24f81fd' into glitch-soc/merge-upstream 2025-11-06 12:35:04 +01:00
diondiondion
58b3fc0379 Refactor "New/Edit list" page to avoid setting state in effect (#36753) 2025-11-06 11:00:37 +00:00
Echo
41a4022988 Fix: correctly dismisses announcement when viewed (#36750) 2025-11-06 09:48:34 +00:00
Emelia Smith
532bb7ea3c Add systemd service file for prometheus exporter (#35130) 2025-11-06 09:25:56 +00:00
Echo
987104f435 Add default visualizer for audio upload without poster (#36734) 2025-11-05 15:33:26 +00:00
Josh Soref
50e1320c8d Improve account migration warnings (#20387)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
Co-authored-by: diondiondion <mail@diondiondion.com>
2025-11-05 15:27:40 +00:00
Echo
6337e036f3 Add new ESLint rule requiring explicit button types (#36738) 2025-11-05 15:11:04 +00:00
Yurii Izorkin
1a31c412ca nginx: optimize location blocks (part 2) (#19644) 2025-11-05 15:08:16 +00:00
Claire
4a6f479535 Update changelog (#36737) 2025-11-05 14:43:22 +00:00
Renaud Chaput
15a7abd581 Resume Renovate updates for tesseract (#36705) 2025-11-05 14:25:40 +00:00
diondiondion
1b8d1cd6e4 Fix spoiler toggle button being able to submit compose form (#36736) 2025-11-05 14:00:42 +00:00
Shlee
35bd985727 Increase nginx.conf proxy_read_timeout (#30599) 2025-11-05 13:36:14 +00:00
Oneric
c0c6f5ea32 Fix Accept headers when fetching AP objects to match spec (#30354) 2025-11-05 13:32:29 +00:00
github-actions[bot]
3aeae8cafd New Crowdin Translations (automated) (#36727)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-05 13:20:34 +00:00
diondiondion
947dfcc548 Add some outer page spacing when viewport width equals content width (#36733) 2025-11-05 12:17:42 +00:00
renovate[bot]
049dcebf9a chore(deps): update devdependencies (non-major) (#36722)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 11:37:25 +00:00
renovate[bot]
f361a2c766 chore(deps): update dependency vite to v7.2.0 (#36729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 11:36:58 +00:00
renovate[bot]
d4ec991126 chore(deps): update dependency aws-sdk-s3 to v1.202.0 (#36488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 11:36:35 +00:00
Matt Jankowski
1f4fe91708 Relax aws-sdk-core version limit (#36719) 2025-11-05 10:43:10 +00:00
Claire
a18d96ae2d Merge pull request #3264 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 26e7fe9771
2025-11-04 21:30:24 +01:00
Claire
9475eeaada [Glitch] Change paste-link-to-quote loading state from generic loading bar to compose placeholder
Port 26e7fe9771 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 21:00:09 +01:00
Claire
e24151f688 [Glitch] Change quote action to error instead of insert link in Private Mentions
Port 1b795c12e9 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:59:48 +01:00
Echo
58158eba00 [Glitch] Quote Posts: Add notifications for DMs and private posts
Port 3ab5ae1e4a to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:58:52 +01:00
Claire
e011d0fc53 [Glitch] Fix Skeleton placeholders being animated when setting to reduce animations is enabled
Port 4a9460f7bd to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:50:18 +01:00
Echo
7d8dc68c5b [Glitch] Refactor: Media Modal
Port 90d4b3b943 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:49:58 +01:00
Echo
649187c30e [Glitch] Remove announcement margin when in Advanced Web Interface
Port 13457111d5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:44:14 +01:00
Claire
4b5282881a [Glitch] Fix quote dropdown menu item in detailed status view
Port 3a54d56fbd to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:43:54 +01:00
Claire
a116d11bc6 [Glitch] Remove option to disable access to local topic feeds for logged-in users
Port b5c550ff0b to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:43:34 +01:00
Jeong Arm
31b72c0600 [Glitch] Reverse 'Hide/Show all' eye icon for thread view
Port b999a626e5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-04 20:43:02 +01:00
Claire
a7ba4ba446 Merge commit '26e7fe97714d077930621f9111b7eaad2774df65' into glitch-soc/merge-upstream 2025-11-04 20:38:24 +01:00
Claire
26e7fe9771 Change paste-link-to-quote loading state from generic loading bar to compose placeholder (#36695) 2025-11-04 19:20:39 +00:00
Claire
1b795c12e9 Change quote action to error instead of insert link in Private Mentions (#36721) 2025-11-04 17:58:50 +00:00
mkljczk
afd5d5c2e5 fix spelling (#35738) 2025-11-04 16:49:12 +00:00
Echo
3ab5ae1e4a Quote Posts: Add notifications for DMs and private posts (#36696) 2025-11-04 16:32:52 +00:00
Claire
4a9460f7bd Fix Skeleton placeholders being animated when setting to reduce animations is enabled (#36716) 2025-11-04 15:30:10 +00:00
renovate[bot]
e7692d0de8 chore(deps): update artifact actions (major) (major) (#36711)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 15:28:26 +00:00
renovate[bot]
cc77844540 chore(deps): update github/codeql-action action to v4 (#36713)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 15:28:17 +00:00
Matt Jankowski
337f16d33e Remove unused DomainControlHelper include from SignedRequest (#35856) 2025-11-04 15:27:42 +00:00
renovate[bot]
ef20dcbf95 chore(deps): update definitelytyped types (non-major) (#36706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 15:01:23 +00:00
renovate[bot]
0c101b47bf chore(deps): update dependency typescript to v5.9.3 (#36707)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:59:42 +00:00
renovate[bot]
f221ce530b chore(deps): update actions/setup-node action to v6 (#36710)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:30:29 +00:00
renovate[bot]
8f1c73ed99 chore(deps): update eslint (non-major) (#36708)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:30:01 +00:00
renovate[bot]
1a698d3b35 chore(deps): update chromaui/action action to v13 (#36712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:29:19 +00:00
renovate[bot]
5a2edebc2b chore(deps): update actions/checkout action to v5 (#36709)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 14:25:48 +00:00
Echo
90d4b3b943 Refactor: Media Modal (#36673) 2025-11-04 13:58:35 +00:00
Echo
13457111d5 Remove announcement margin when in Advanced Web Interface (#36714) 2025-11-04 13:37:34 +00:00
Claire
3a54d56fbd Fix quote dropdown menu item in detailed status view (#36704) 2025-11-04 11:01:25 +00:00
Claire
b5c550ff0b Remove option to disable access to local topic feeds for logged-in users (#36703) 2025-11-04 10:37:43 +00:00
renovate[bot]
6c176e56ee chore(deps): update dependency opentelemetry-instrumentation-pg to '~> 0.33.0' (#36701)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 10:36:04 +00:00
Jeong Arm
b999a626e5 Reverse 'Hide/Show all' eye icon for thread view (#22301) 2025-11-04 10:35:50 +00:00
renovate[bot]
bb084da1f5 fix(deps): update dependency pino-http to v11 (#36359)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 10:28:30 +00:00
renovate[bot]
84e351cc3a chore(deps): update dependency shoulda-matchers to v7 (#36680)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 10:21:27 +00:00
renovate[bot]
7fced55ce7 fix(deps): update dependency pino to v10 (#36357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 09:56:12 +00:00
Matt Jankowski
8f37f9d012 Update vitest to version 4.0.5 (#36652) 2025-11-04 09:47:30 +00:00
Matt Jankowski
8e4c9cf933 Update lint-staged to version 16.2.6 (#36668) 2025-11-04 09:43:38 +00:00
Matt Jankowski
cf87da25ad Update storybook to version 10.0.2 (#36657) 2025-11-04 09:42:27 +00:00
renovate[bot]
966aaaaf56 chore(deps): update dependency sidekiq to v8.0.9 (#36699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 09:41:59 +00:00
renovate[bot]
5b880a2046 chore(deps): update dependency brakeman to v7.1.1 (#35434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 09:32:38 +00:00
renovate[bot]
24aa5d0460 fix(deps): update dependency @rails/ujs to v7.1.600 (#36634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-04 08:41:19 +00:00
Claire
5ac3cceaf5 Increase number of quote approval job retries (#36698) 2025-11-04 08:29:27 +00:00
github-actions[bot]
e5fbb49033 New Crowdin Translations (automated) (#36697)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-04 08:10:20 +00:00
Claire
310ae6317e Merge pull request #3262 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to d1f57822af
2025-11-03 21:31:16 +01:00
Claire
5c7d22e60a [Glitch] Disable paste-link-to-quote flow when composing Private Mentions
Port bae5877c84 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-11-03 21:09:40 +01:00
Claire
8d1208224f Merge commit 'd1f57822af0da2b2836e33baab5f89469ac6fa25' into glitch-soc/merge-upstream 2025-11-03 21:04:45 +01:00
Rachael Wright-Munn
d1f57822af Move "Privacy and reach" from "Public profile" to top-level navigation (#27294) 2025-11-03 17:56:17 +00:00
Claire
9b3e92bf17 Prevent creation of Private Mentions quoting someone who is not mentioned (#36689) 2025-11-03 14:16:25 +00:00
Claire
e79e42f8f1 Fix issuance of quote approval for remote private statuses (#36693) 2025-11-03 14:15:18 +00:00
Claire
bae5877c84 Disable paste-link-to-quote flow when composing Private Mentions (#36690) 2025-11-03 13:56:07 +00:00
github-actions[bot]
61c0daffc9 New Crowdin Translations (automated) (#36676)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-11-03 12:21:04 +00:00
renovate[bot]
f10c79c8d1 chore(deps): update dependency irb to v1.15.3 (#36682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 11:05:26 +00:00
renovate[bot]
8781abf2bd chore(deps): update dependency sass to v1.93.3 (#36674)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 09:26:54 +00:00
renovate[bot]
7faf2eaa79 chore(deps): update dependency jsdom to v27.1.0 (#36663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 09:23:25 +00:00
renovate[bot]
0bf974a758 chore(deps): update dependency haml_lint to v0.67.0 (#36645)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 09:21:51 +00:00
renovate[bot]
5c0c77223b chore(deps): update node.js to 24.11 (#36630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 09:21:07 +00:00
renovate[bot]
5fe74d2092 chore(deps): update dependency rubyzip to v3.2.2 (#36687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 09:09:54 +00:00
Claire
6dff6ae7f3 Merge pull request #3259 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 055f581ca5
2025-10-31 18:55:20 +01:00
diondiondion
2ab482da18 [Glitch] Fix initially selected language in Rules panel, hide selector when no alternative translations exist
Port 055f581ca5 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 18:15:48 +01:00
diondiondion
a0686536c6 [Glitch] Add separate translation key for "About this server" string
Port 499ddfe8e1 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 18:15:25 +01:00
diondiondion
3d80e8b021 [Glitch] Show error when submitting empty post rather than failing silently
Port fcecbf31ed to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 18:14:58 +01:00
Echo
43fbff50b5 [Glitch] Fix: Ensure carousel focuses on wrapper
Port 28cb345131 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 18:13:59 +01:00
Echo
9f8e812c56 [Glitch] Refactor carousel components
Port e7cd5a430e to glitch-soc

Co-authored-by: diondiondion <mail@diondiondion.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
2025-10-31 18:13:35 +01:00
Claire
6ff4dad89d Merge commit '055f581ca58b62132c1eff23453031d9df9dbf0e' into glitch-soc/merge-upstream 2025-10-31 18:03:21 +01:00
diondiondion
055f581ca5 Fix initially selected language in Rules panel, hide selector when no alternative translations exist (#36672) 2025-10-31 14:20:59 +00:00
Claire
8a2826604c Bump version to v4.6.0-alpha.1 (#36667) 2025-10-31 13:24:26 +00:00
Matt Jankowski
d865a095d0 Update eslint-plugin-jsdoc to version 61.1.11 (#36653) 2025-10-31 11:07:48 +00:00
renovate[bot]
35abaa7ff1 chore(deps): update dependency axios to v1.13.1 (#36633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 10:31:57 +00:00
renovate[bot]
fd4e51b3d8 chore(deps): update dependency libvips to v8.17.3 (#36654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 10:30:55 +00:00
renovate[bot]
2c4367bcfc chore(deps): update dependency rubocop to v1.81.7 (#36662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 10:24:36 +00:00
github-actions[bot]
d47ca1cc36 New Crowdin Translations (automated) (#36660)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-10-31 10:24:16 +00:00
diondiondion
499ddfe8e1 Add separate translation key for "About this server" string (#36664) 2025-10-31 10:07:10 +00:00
Matt Jankowski
7b61ad936d Update playwright-ruby-client to version 1.56.0 (#36655) 2025-10-31 09:52:23 +00:00
diondiondion
fcecbf31ed Show error when submitting empty post rather than failing silently (#36650) 2025-10-30 19:29:25 +00:00
Matt Jankowski
aefd728309 Use before_action to protect hidden collections in following/followers lists (#35783) 2025-10-30 16:34:19 +00:00
renovate[bot]
13a070f8d1 chore(deps): update dependency webmock to v3.26.1 (#36648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 16:03:47 +00:00
Echo
28cb345131 Fix: Ensure carousel focuses on wrapper (#36649) 2025-10-30 13:08:24 +00:00
Echo
f3d9a4ed44 Add CSS Module support (#36637) 2025-10-30 12:30:42 +00:00
Claire
762e87b121 Fix SMTP configuration with mail 2.9.0 (#36646) 2025-10-30 11:21:32 +00:00
Joshua Byrd
e5e9f8da93 Fix og:images from The Guardian (and possibly other CDNs that check URL hashes) (#36139)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2025-10-30 10:57:07 +00:00
Echo
ff1e19a506 Silence Storybook build warning (#36647) 2025-10-30 10:51:34 +00:00
renovate[bot]
2c5d3f934c chore(deps): update dependency oj to v3.16.12 (#36644)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 08:13:50 +00:00
github-actions[bot]
a77038b288 New Crowdin Translations (automated) (#36641)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-10-30 07:52:39 +00:00
Dima
ebf5cee38e Fix media URL inconsistency when deleting statuses via API (#35880) 2025-10-29 16:46:16 +00:00
Echo
e7cd5a430e Refactor carousel components (#36425)
Co-authored-by: diondiondion <mail@diondiondion.com>
2025-10-29 14:44:46 +00:00
1082 changed files with 23202 additions and 19031 deletions

View File

@@ -73,7 +73,7 @@ services:
hard: -1
libretranslate:
image: libretranslate/libretranslate:v1.6.2
image: libretranslate/libretranslate:v1.7.3
restart: unless-stopped
volumes:
- lt-data:/home/libretranslate/.local

View File

@@ -9,7 +9,7 @@ runs:
using: 'composite'
steps:
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'

View File

@@ -5,7 +5,6 @@
'customManagers:dockerfileVersions',
':labels(dependencies)',
':prConcurrentLimitNone', // Remove limit for open PRs at any time.
':prHourlyLimit2', // Rate limit PR creation to a maximum of two per hour.
':enableVulnerabilityAlertsWithLabel(security)',
],
rebaseWhen: 'conflicted',
@@ -23,8 +22,6 @@
// Require Dependency Dashboard Approval for major version bumps of these node packages
matchManagers: ['npm'],
matchPackageNames: [
'tesseract.js', // Requires code changes
// react-router: Requires manual upgrade
'history',
'react-router-dom',

View File

@@ -35,7 +35,7 @@ jobs:
- linux/arm64
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Prepare
env:
@@ -100,7 +100,7 @@ jobs:
- name: Upload digest
if: ${{ inputs.push_to_images != '' }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
# `hashFiles` is used to disambiguate between streaming and non-streaming images
name: digests-${{ hashFiles(inputs.file_to_build) }}-${{ env.PLATFORM_PAIR }}
@@ -119,10 +119,10 @@ jobs:
PUSH_TO_IMAGES: ${{ inputs.push_to_images }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Download digests
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
path: ${{ runner.temp }}/digests
# `hashFiles` is used to disambiguate between streaming and non-streaming images

View File

@@ -18,7 +18,7 @@ jobs:
steps:
# Repository needs to be cloned so `git rev-parse` below works
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- id: version_vars
run: |
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT

View File

@@ -28,7 +28,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Ruby
uses: ruby/setup-ruby@v1

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby

View File

@@ -1,31 +1,51 @@
name: 'Chromatic'
permissions:
contents: read
on:
push:
branches-ignore:
- renovate/*
- stable-*
paths:
- 'package.json'
- 'yarn.lock'
- '**/*.js'
- '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
- '**/*.css'
- '**/*.scss'
- '.github/workflows/chromatic.yml'
jobs:
pathcheck:
name: Check for relevant changes
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.filter.outputs.src }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
src:
- 'package.json'
- 'yarn.lock'
- '**/*.js'
- '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
- '**/*.css'
- '**/*.scss'
- '.github/workflows/chromatic.yml'
chromatic:
name: Run Chromatic
runs-on: ubuntu-latest
if: github.repository == 'mastodon/mastodon'
needs: pathcheck
if: github.repository == 'mastodon/mastodon' && needs.pathcheck.outputs.changed == 'true'
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
@@ -33,9 +53,10 @@ jobs:
run: yarn build-storybook
- name: Run Chromatic
uses: chromaui/action@v12
uses: chromaui/action@v13
with:
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
zip: true
storybookBuildDir: 'storybook-static'
exitZeroOnChanges: false # Fail workflow if changes are found
autoAcceptChanges: 'main' # Auto-accept changes on main branch only

View File

@@ -31,11 +31,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -48,7 +48,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v4
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -61,6 +61,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: '/language:${{matrix.language}}'

View File

@@ -13,7 +13,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Increase Git http.postBuffer
# This is needed due to a bug in Ubuntu's cURL version?

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Increase Git http.postBuffer
# This is needed due to a bug in Ubuntu's cURL version?

View File

@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: crowdin action
uses: crowdin/github-action@v2

View File

@@ -13,7 +13,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -34,7 +34,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -33,7 +33,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Ruby
uses: ruby/setup-ruby@v1

View File

@@ -38,7 +38,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -35,7 +35,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Ruby
uses: ruby/setup-ruby@v1

View File

@@ -34,7 +34,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript

View File

@@ -72,7 +72,7 @@ jobs:
BUNDLE_RETRY: 3
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby

View File

@@ -32,7 +32,7 @@ jobs:
SECRET_KEY_BASE_DUMMY: 1
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
@@ -65,7 +65,7 @@ jobs:
run: |
tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs* tmp/cache/vite/last-build*.json
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
if: matrix.mode == 'test'
with:
path: |-
@@ -128,9 +128,9 @@ jobs:
- '3.3'
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
path: './'
name: ${{ github.sha }}
@@ -230,9 +230,9 @@ jobs:
- '3.3'
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
path: './'
name: ${{ github.sha }}
@@ -309,9 +309,9 @@ jobs:
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
path: './'
name: ${{ github.sha }}
@@ -350,14 +350,14 @@ jobs:
- run: bin/rspec spec/system --tag streaming --tag js
- name: Archive logs
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
with:
name: e2e-logs-${{ matrix.ruby-version }}
path: log/
- name: Archive test screenshots
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
with:
name: e2e-screenshots-${{ matrix.ruby-version }}
@@ -447,9 +447,9 @@ jobs:
search-image: opensearchproject/opensearch:2
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
path: './'
name: ${{ github.sha }}
@@ -469,14 +469,14 @@ jobs:
- run: bin/rspec --tag search
- name: Archive logs
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
with:
name: test-search-logs-${{ matrix.ruby-version }}
path: log/
- name: Archive test screenshots
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: failure()
with:
name: test-search-screenshots

2
.nvmrc
View File

@@ -1 +1 @@
24.10
24.12

View File

@@ -95,6 +95,7 @@ AUTHORS.md
# Ignore glitch-soc vendored CSS reset
app/javascript/flavours/glitch/styles/reset.scss
app/javascript/flavours/glitch/styles_new/mastodon/reset.scss
# Ignore win95 theme
app/javascript/styles/win95.scss

View File

@@ -1 +1 @@
3.4.7
3.4.8

View File

@@ -27,11 +27,12 @@ const config: StorybookConfig = {
'oops.gif',
'oops.png',
].map((path) => ({ from: `../public/${path}`, to: `/${path}` })),
{ from: '../app/javascript/images/logo.svg', to: '/custom-emoji/logo.svg' },
],
viteFinal(config) {
// For an unknown reason, Storybook does not use the root
// from the Vite config so we need to set it manually.
config.root = resolve(__dirname, '../app/javascript');
config.root = resolve(import.meta.dirname, '../app/javascript');
return config;
},
};

View File

@@ -1,2 +1,2 @@
<html class="no-reduce-motion">
<html class="no-reduce-motion theme-light">
</html>

View File

@@ -11,6 +11,11 @@ import type { Preview } from '@storybook/react-vite';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { action } from 'storybook/actions';
import {
importCustomEmojiData,
importLegacyShortcodes,
importEmojiData,
} from '@/mastodon/features/emoji/loader';
import type { LocaleData } from '@/mastodon/locales';
import { reducerWithInitialState } from '@/mastodon/reducers';
import { defaultMiddleware } from '@/mastodon/store/store';
@@ -50,12 +55,31 @@ const preview: Preview = {
locale: 'en',
},
decorators: [
(Story, { parameters, globals, args }) => {
(Story, { parameters, globals, args, argTypes }) => {
// Get the locale from the global toolbar
// and merge it with any parameters or args state.
const { locale } = globals as { locale: string };
const { state = {} } = parameters;
const { state: argsState = {} } = args;
const argsState: Record<string, unknown> = {};
for (const [key, value] of Object.entries(args)) {
const argType = argTypes[key];
if (argType?.reduxPath) {
const reduxPath = Array.isArray(argType.reduxPath)
? argType.reduxPath.map((p) => p.toString())
: argType.reduxPath.split('.');
reduxPath.reduce((acc, key, i) => {
if (acc[key] === undefined) {
acc[key] = {};
}
if (i === reduxPath.length - 1) {
acc[key] = value;
}
return acc[key] as Record<string, unknown>;
}, argsState);
}
}
const reducer = reducerWithInitialState(
{
@@ -64,7 +88,7 @@ const preview: Preview = {
},
},
state as Record<string, unknown>,
argsState as Record<string, unknown>,
argsState,
);
const store = configureStore({
@@ -127,7 +151,12 @@ const preview: Preview = {
</MemoryRouter>
),
],
loaders: [mswLoader],
loaders: [
mswLoader,
importCustomEmojiData,
importLegacyShortcodes,
({ globals: { locale } }) => importEmojiData(locale as string),
],
parameters: {
layout: 'centered',

View File

@@ -7,7 +7,7 @@
* - Please do NOT modify this file.
*/
const PACKAGE_VERSION = '2.11.3'
const PACKAGE_VERSION = '2.12.1'
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
@@ -205,6 +205,7 @@ async function resolveMainClient(event) {
* @param {FetchEvent} event
* @param {Client | undefined} client
* @param {string} requestId
* @param {number} requestInterceptedAt
* @returns {Promise<Response>}
*/
async function getResponse(event, client, requestId, requestInterceptedAt) {

View File

@@ -1,7 +1,20 @@
// The addon package.json incorrectly exports types, so we need to override them here.
import type { RootState } from '@/mastodon/store';
// 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';
}
type RootPathKeys = keyof RootState;
declare module 'storybook/internal/csf' {
export interface InputType {
reduxPath?:
| `${RootPathKeys}.${string}`
| [RootPathKeys, ...(string | number)[]];
}
}
export {};

View File

@@ -1,13 +0,0 @@
diff --git a/lib/index.js b/lib/index.js
index 16ed6be8be8f555cc99096c2ff60954b42dc313d..d009c069770d066ad0db7ad02de1ea473a29334e 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -99,7 +99,7 @@ function lodash(_ref) {
var node = _ref3;
- if ((0, _types.isModuleDeclaration)(node)) {
+ if ((0, _types.isImportDeclaration)(node) || (0, _types.isExportDeclaration)(node)) {
isModule = true;
break;
}

View File

@@ -538,7 +538,7 @@ and provided thanks to the work of the following contributors:
* [Drew Schuster](mailto:dtschust@gmail.com)
* [Dryusdan](mailto:dryusdan@dryusdan.fr)
* [Eai](mailto:eai@mizle.net)
* [Eashwar Ranganathan](mailto:eranganathan@lyft.com)
* [Eashwar Ranganathan](mailto:eashwar@eashwar.com)
* [Ed Knutson](mailto:knutsoned@gmail.com)
* [Elizabeth Martín Campos](mailto:me@elizabeth.sh)
* [Elizabeth Myers](mailto:elizabeth@interlinked.me)

View File

@@ -2,77 +2,6 @@
All notable changes to this project will be documented in this file.
## [4.5.6] - 2026-02-03
### Security
- Fix ActivityPub collection caching logic for pinned posts and featured tags not checking blocked accounts ([GHSA-ccpr-m53r-mfwr](https://github.com/mastodon/mastodon/security/advisories/GHSA-ccpr-m53r-mfwr))
### Changed
- Shorten caching of quote posts pending approval (#37570 and #37592 by @ClearlyClaire)
### Fixed
- Fix relationship cache not being cleared when handling account migrations (#37664 by @ClearlyClaire)
- Fix quote cancel button not appearing after edit then delete-and-redraft (#37066 by @PGrayCS)
- Fix followers with profile subscription (bell icon) being notified of post edits (#37646 by @ClearlyClaire)
- Fix error when encountering invalid tag in updated object (#37635 by @ClearlyClaire)
- Fix cross-server conversation tracking (#37559 by @ClearlyClaire)
- Fix recycled connections not being immediately closed (#37335 and #37674 by @ClearlyClaire and @shleeable)
## [4.5.5] - 2026-01-20
### Security
- Fix missing limits on various federated properties [GHSA-gg8q-rcg7-p79g](https://github.com/mastodon/mastodon/security/advisories/GHSA-gg8q-rcg7-p79g)
- Fix remote user suspension bypass [GHSA-5h2f-wg8j-xqwp](https://github.com/mastodon/mastodon/security/advisories/GHSA-5h2f-wg8j-xqwp)
- Fix missing length limits on some user-provided fields [GHSA-6x3w-9g92-gvf3](https://github.com/mastodon/mastodon/security/advisories/GHSA-6x3w-9g92-gvf3)
- Fix missing access check for push notification settings update [GHSA-f3q8-7vw3-69v4](https://github.com/mastodon/mastodon/security/advisories/GHSA-f3q8-7vw3-69v4)
### Changed
- Skip tombstone creation on deleting from 404 (#37533 by @ClearlyClaire)
### Fixed
- Fix potential duplicate handling of quote accept/reject/delete (#37537 by @ClearlyClaire)
- Fix `FeedManager#filter_from_home` error when handling a reblog of a deleted status (#37486 by @ClearlyClaire)
- Fix needlessly complicated SQL query in status batch removal (#37469 by @ClearlyClaire)
- Fix `quote_approval_policy` being reset to user defaults when omitted in status update (#37436 and #37474 by @mjankowski and @shleeable)
- Fix `Vary` parsing in cache control enforcement (#37426 by @MegaManSec)
- Fix missing URI scheme test in `QuoteRequest` handling (#37425 by @MegaManSec)
- Fix thread-unsafe ActivityPub activity dispatch (#37423 by @MegaManSec)
- Fix URI generation for reblogs by accounts with numerical ActivityPub identifiers (#37415 by @oneiros)
- Fix SignatureParser accepting duplicate parameters in HTTP Signature header (#37375 by @shleeable)
- Fix emoji with variant selector not being rendered properly (#37320 by @ChaosExAnima)
- Fix mobile admin sidebar displaying under batch table toolbar (#37307 by @diondiondion)
## [4.5.4] - 2026-01-07
### Security
- Fix SSRF protection bypass ([GHSA](https://github.com/mastodon/mastodon/security/advisories/GHSA-xfrj-c749-jxxq))
- Fix missing ownership check in severed relationships controller ([GHSA](https://github.com/mastodon/mastodon/security/advisories/GHSA-ww85-x9cp-5v24))
### Changed
- Change HTTP Signature verification status from 401 to 503 on temporary failure to get remote actor (#37221 by @ClearlyClaire)
### Fixed
- Fix custom emojis not being rendered in profile fields (#37365 by @ClearlyClaire)
- Fix serialization of context pages (#37376 by @ClearlyClaire)
- Fix quotes with CWs but no text not having fallback link (#37361 by @ClearlyClaire)
- Fix outdated link target for “locked” warning (#37366 by @ClearlyClaire)
- Fix local custom emojis sometimes being rendered in remote posts (#37284 by @ChaosExAnima)
- Fix some assets not being loaded from configured CDN (#37310 by @ChaosExAnima)
- Fix notifications page error in Tor browser (#37285 by @diondiondion)
- Fix custom emojis not being displayed in CWs and fav/boost notifications (#37272 and #37306 by @ChaosExAnima and @ClearlyClaire)
- Fix default `Admin` role not including `view_feeds` permission (#37301 by @ClearlyClaire)
- Fix hashtag autocomplete replacing suggestion's first characters with input (#37281 by @ClearlyClaire)
- Fix mentions of domain-blocked users being processed (#37257 by @ClearlyClaire)
## [4.5.3] - 2025-12-08
### Security

View File

@@ -13,7 +13,7 @@ ARG BASE_REGISTRY="docker.io"
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
# renovate: datasource=docker depName=docker.io/ruby
ARG RUBY_VERSION="3.4.7"
ARG RUBY_VERSION="3.4.8"
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="22"]
# renovate: datasource=node-version depName=node
ARG NODE_MAJOR_VERSION="24"

View File

@@ -48,22 +48,3 @@ Mastodon requires all `POST` requests to be signed, and MAY require `GET` reques
### Additional documentation
- [Mastodon documentation](https://docs.joinmastodon.org/)
## Size limits
Mastodon imposes a few hard limits on federated content.
These limits are intended to be very generous and way above what the Mastodon user experience is optimized for, so as to accomodate future changes and unusual or unforeseen usage patterns, while still providing some limits for performance reasons.
The following table attempts to summary those limits.
| Limited property | Size limit | Consequence of exceeding the limit |
| ------------------------------------------------------------- | ---------- | ---------------------------------- |
| Serialized JSON-LD | 1MB | **Activity is rejected/dropped** |
| Profile fields (actor `PropertyValue` attachments) name/value | 2047 | Field name/value is truncated |
| Number of profile fields (actor `PropertyValue` attachments) | 50 | Fields list is truncated |
| Poll options (number of `anyOf`/`oneOf` in a `Question`) | 500 | Items list is truncated |
| Account username (actor `preferredUsername`) length | 2048 | **Actor will be rejected** |
| Account display name (actor `name`) length | 2048 | Display name will be truncated |
| Account note (actor `summary`) length | 20kB | Account note will be truncated |
| Account `attributionDomains` | 256 | List will be truncated |
| Account aliases (actor `alsoKnownAs`) | 256 | List will be truncated |
| Custom emoji shortcode (`Emoji` `name`) | 2048 | Emoji will be rejected |

12
Gemfile
View File

@@ -13,7 +13,7 @@ gem 'haml-rails', '~>3.0'
gem 'pg', '~> 1.5'
gem 'pghero'
gem 'aws-sdk-core', '< 3.216.0', require: false # TODO: https://github.com/mastodon/mastodon/pull/34173#issuecomment-2733378873
gem 'aws-sdk-core', require: false
gem 'aws-sdk-s3', '~> 1.123', require: false
gem 'blurhash', '~> 0.1'
gem 'fog-core', '<= 2.6.0'
@@ -24,7 +24,7 @@ gem 'ruby-vips', '~> 2.2', require: false
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
gem 'bootsnap', '~> 1.18.0', require: false
gem 'bootsnap', '~> 1.19.0', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.3'
@@ -40,7 +40,7 @@ gem 'net-ldap', '~> 0.18'
gem 'omniauth', '~> 2.0'
gem 'omniauth-cas', '~> 3.0.0.beta.1'
gem 'omniauth_openid_connect', '~> 0.8.0'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'omniauth-rails_csrf_protection', '~> 2.0'
gem 'omniauth-saml', '~> 2.0'
gem 'color_diff', '~> 0.1'
@@ -71,7 +71,7 @@ gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14'
gem 'parslet'
gem 'premailer-rails'
gem 'public_suffix', '~> 6.0'
gem 'public_suffix', '~> 7.0'
gem 'pundit', '~> 2.3'
gem 'rack-attack', '~> 6.6'
gem 'rack-cors', require: 'rack/cors'
@@ -114,7 +114,7 @@ group :opentelemetry do
gem 'opentelemetry-instrumentation-http', '~> 0.27.0', require: false
gem 'opentelemetry-instrumentation-http_client', '~> 0.26.0', require: false
gem 'opentelemetry-instrumentation-net_http', '~> 0.26.0', require: false
gem 'opentelemetry-instrumentation-pg', '~> 0.32.0', require: false
gem 'opentelemetry-instrumentation-pg', '~> 0.34.0', require: false
gem 'opentelemetry-instrumentation-rack', '~> 0.29.0', require: false
gem 'opentelemetry-instrumentation-rails', '~> 0.39.0', require: false
gem 'opentelemetry-instrumentation-redis', '~> 0.28.0', require: false
@@ -138,7 +138,7 @@ group :test do
# Browser integration testing
gem 'capybara', '~> 3.39'
gem 'capybara-playwright-driver'
gem 'playwright-ruby-client', '1.55.0', require: false # Pinning the exact version as it needs to be kept in sync with the installed npm package
gem 'playwright-ruby-client', '1.57.0', require: false # Pinning the exact version as it needs to be kept in sync with the installed npm package
# Used to reset the database between system tests
gem 'database_cleaner-active_record'

View File

@@ -53,7 +53,7 @@ GEM
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
active_model_serializers (0.10.15)
active_model_serializers (0.10.16)
actionpack (>= 4.1)
activemodel (>= 4.1)
case_transform (>= 0.2)
@@ -86,8 +86,8 @@ GEM
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
addressable (2.8.8)
public_suffix (>= 2.0.2, < 8.0)
aes_key_wrap (1.1.0)
android_key_attestation (0.3.0)
annotaterb (4.20.0)
@@ -96,17 +96,20 @@ GEM
ast (2.4.3)
attr_required (1.0.2)
aws-eventstream (1.4.0)
aws-partitions (1.1168.0)
aws-sdk-core (3.215.1)
aws-partitions (1.1194.0)
aws-sdk-core (3.239.2)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
bigdecimal
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.96.0)
aws-sdk-core (~> 3, >= 3.210.0)
logger
aws-sdk-kms (1.118.0)
aws-sdk-core (~> 3, >= 3.239.1)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.177.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sdk-s3 (1.207.0)
aws-sdk-core (~> 3, >= 3.234.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
@@ -126,14 +129,14 @@ GEM
binding_of_caller (1.0.1)
debug_inspector (>= 1.2.0)
blurhash (0.1.8)
bootsnap (1.18.6)
bootsnap (1.19.0)
msgpack (~> 1.2)
brakeman (7.1.1)
racc
browser (6.2.0)
builder (3.3.0)
bundler-audit (0.9.2)
bundler (>= 1.2.0, < 3)
bundler-audit (0.9.3)
bundler (>= 1.2.0)
thor (~> 1.0)
capybara (3.40.0)
addressable
@@ -163,8 +166,8 @@ GEM
climate_control (1.2.0)
cocoon (1.2.15)
color_diff (0.1)
concurrent-ruby (1.3.5)
connection_pool (2.5.4)
concurrent-ruby (1.3.6)
connection_pool (2.5.5)
cose (1.3.1)
cbor (~> 0.5.9)
openssl-signature_algorithm (~> 1.0)
@@ -179,7 +182,7 @@ GEM
activerecord (>= 5.a)
database_cleaner-core (~> 2.0)
database_cleaner-core (2.0.1)
date (3.4.1)
date (3.5.1)
debug (1.11.0)
irb (~> 1.10)
reline (>= 0.3.8)
@@ -205,7 +208,7 @@ GEM
domain_name (0.6.20240107)
doorkeeper (5.8.2)
railties (>= 5)
dotenv (3.1.8)
dotenv (3.2.0)
drb (2.2.3)
dry-cli (1.3.0)
elasticsearch (7.17.11)
@@ -224,14 +227,14 @@ GEM
mail (~> 2.7)
email_validator (2.2.4)
activemodel
erb (5.1.3)
erb (6.0.1)
erubi (1.13.1)
et-orbi (1.4.0)
tzinfo
excon (1.3.0)
excon (1.3.2)
logger
fabrication (3.0.0)
faker (3.5.2)
faker (3.5.3)
i18n (>= 1.8.11, < 2)
faraday (2.14.0)
faraday-net_http (>= 2.0, < 3.5)
@@ -241,8 +244,8 @@ GEM
faraday (>= 1, < 3)
faraday-httpclient (2.0.2)
httpclient (>= 2.2)
faraday-net_http (3.4.1)
net-http (>= 0.5.0)
faraday-net_http (3.4.2)
net-http (~> 0.5)
fast_blank (1.0.1)
fastimage (2.4.0)
ffi (1.17.2)
@@ -266,20 +269,20 @@ GEM
fog-openstack (1.1.5)
fog-core (~> 2.1)
fog-json (>= 1.0)
formatador (1.2.1)
formatador (1.2.3)
reline
forwardable (1.3.3)
fugit (1.12.0)
fugit (1.12.1)
et-orbi (~> 1.4)
raabro (~> 1.4)
globalid (1.3.0)
activesupport (>= 6.1)
google-protobuf (4.32.1)
google-protobuf (4.33.2)
bigdecimal
rake (>= 13)
googleapis-common-protos-types (1.22.0)
google-protobuf (~> 4.26)
haml (6.3.0)
haml (7.1.0)
temple (>= 0.8.2)
thor
tilt
@@ -288,7 +291,7 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.66.0)
haml_lint (0.68.0)
haml (>= 5.0)
parallel (~> 1.10)
rainbow
@@ -301,8 +304,8 @@ GEM
highline (3.1.2)
reline
hiredis (0.6.3)
hiredis-client (0.26.1)
redis-client (= 0.26.1)
hiredis-client (0.26.2)
redis-client (= 0.26.2)
hkdf (0.3.0)
htmlentities (4.3.4)
http (5.3.1)
@@ -321,13 +324,14 @@ GEM
rainbow (>= 2.0.0)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
i18n-tasks (1.0.15)
i18n-tasks (1.1.2)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
erubi
highline (>= 2.0.0)
highline (>= 3.0.0)
i18n
parser (>= 3.2.2.1)
prism
rails-i18n
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.8, >= 1.8.1)
@@ -336,7 +340,7 @@ GEM
inline_svg (1.10.0)
activesupport (>= 3.0)
nokogiri (>= 1.6)
io-console (0.8.1)
io-console (0.8.2)
irb (1.15.3)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
@@ -346,7 +350,7 @@ GEM
azure-blob (~> 0.5.2)
hashie (~> 5.0)
jmespath (1.6.2)
json (2.15.1)
json (2.18.0)
json-canonicalization (1.0.0)
json-jwt (1.17.0)
activesupport (>= 4.2)
@@ -443,13 +447,13 @@ GEM
mime-types-data (3.2025.0924)
mini_mime (1.1.5)
mini_portile2 (2.8.9)
minitest (5.26.0)
minitest (5.27.0)
msgpack (1.8.0)
multi_json (1.17.0)
multi_json (1.18.0)
mutex_m (0.3.0)
net-http (0.6.0)
uri
net-imap (0.5.12)
net-imap (0.6.0)
date
net-protocol
net-ldap (0.20.0)
@@ -461,11 +465,11 @@ GEM
timeout
net-smtp (0.5.1)
net-protocol
nio4r (2.7.4)
nio4r (2.7.5)
nokogiri (1.18.10)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
oj (3.16.11)
oj (3.16.13)
bigdecimal (>= 3.0)
ostruct (>= 0.2)
omniauth (2.1.4)
@@ -477,7 +481,7 @@ GEM
addressable (~> 2.8)
nokogiri (~> 1.12)
omniauth (~> 2.1)
omniauth-rails_csrf_protection (1.0.2)
omniauth-rails_csrf_protection (2.0.1)
actionpack (>= 4.2)
omniauth (~> 2.0)
omniauth-saml (2.2.4)
@@ -512,9 +516,9 @@ GEM
opentelemetry-common (~> 0.20)
opentelemetry-sdk (~> 1.10)
opentelemetry-semantic_conventions
opentelemetry-helpers-sql (0.2.0)
opentelemetry-helpers-sql (0.3.0)
opentelemetry-api (~> 1.7)
opentelemetry-helpers-sql-obfuscation (0.4.0)
opentelemetry-helpers-sql-processor (0.3.1)
opentelemetry-common (~> 0.21)
opentelemetry-instrumentation-action_mailer (0.6.1)
opentelemetry-instrumentation-active_support (~> 0.10)
@@ -538,19 +542,19 @@ GEM
opentelemetry-registry (~> 0.1)
opentelemetry-instrumentation-concurrent_ruby (0.24.0)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-excon (0.26.0)
opentelemetry-instrumentation-excon (0.26.1)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-faraday (0.30.0)
opentelemetry-instrumentation-faraday (0.30.1)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-http (0.27.0)
opentelemetry-instrumentation-http (0.27.1)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-http_client (0.26.0)
opentelemetry-instrumentation-http_client (0.26.1)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-net_http (0.26.0)
opentelemetry-instrumentation-net_http (0.26.1)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-pg (0.32.0)
opentelemetry-instrumentation-pg (0.34.1)
opentelemetry-helpers-sql
opentelemetry-helpers-sql-obfuscation
opentelemetry-helpers-sql-processor
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-rack (0.29.0)
opentelemetry-instrumentation-base (~> 0.25)
@@ -565,7 +569,7 @@ GEM
opentelemetry-instrumentation-concurrent_ruby (~> 0.23)
opentelemetry-instrumentation-redis (0.28.0)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-instrumentation-sidekiq (0.28.0)
opentelemetry-instrumentation-sidekiq (0.28.1)
opentelemetry-instrumentation-base (~> 0.25)
opentelemetry-registry (0.4.0)
opentelemetry-api (~> 1.1)
@@ -581,7 +585,7 @@ GEM
ox (2.14.23)
bigdecimal (>= 3.0)
parallel (1.27.0)
parser (3.3.9.0)
parser (3.3.10.0)
ast (~> 2.4.1)
racc
parslet (2.0.0)
@@ -590,7 +594,7 @@ GEM
pg (1.6.2)
pghero (3.7.0)
activerecord (>= 7.1)
playwright-ruby-client (1.55.0)
playwright-ruby-client (1.57.0)
concurrent-ruby (>= 1.1.6)
mime-types (>= 3.0)
pp (0.6.3)
@@ -604,17 +608,17 @@ GEM
net-smtp
premailer (~> 1.7, >= 1.7.9)
prettyprint (0.2.0)
prism (1.5.2)
prometheus_exporter (2.3.0)
prism (1.6.0)
prometheus_exporter (2.3.1)
webrick
propshaft (1.3.1)
actionpack (>= 7.0.0)
activesupport (>= 7.0.0)
rack
psych (5.2.6)
psych (5.3.0)
date
stringio
public_suffix (6.0.2)
public_suffix (7.0.0)
puma (7.1.0)
nio4r (~> 2.0)
pundit (2.5.2)
@@ -627,14 +631,14 @@ GEM
rack-cors (3.0.0)
logger
rack (>= 3.0.14)
rack-oauth2 (2.2.1)
rack-oauth2 (2.3.0)
activesupport
attr_required
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-protection (4.1.1)
rack-protection (4.2.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
@@ -645,7 +649,7 @@ GEM
rack (>= 3.0.0)
rack-test (2.2.0)
rack (>= 1.3)
rackup (2.2.1)
rackup (2.3.1)
rack (>= 3)
rails (8.0.3)
actioncable (= 8.0.3)
@@ -668,7 +672,7 @@ GEM
rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
rails-i18n (8.0.2)
rails-i18n (8.1.0)
i18n (>= 0.7, < 2)
railties (>= 8.0.0, < 9)
railties (8.0.3)
@@ -681,7 +685,7 @@ GEM
tsort (>= 0.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.3.0)
rake (13.3.1)
rdf (3.3.4)
bcp47_spec (~> 0.2)
bigdecimal (~> 3.1, >= 3.1.5)
@@ -691,7 +695,7 @@ GEM
readline (~> 0.0)
rdf-normalize (0.7.0)
rdf (~> 3.3)
rdoc (6.15.1)
rdoc (6.17.0)
erb
psych (>= 4.0.0)
tsort
@@ -699,10 +703,10 @@ GEM
reline
redcarpet (3.6.1)
redis (4.8.1)
redis-client (0.26.1)
redis-client (0.26.2)
connection_pool
regexp_parser (2.11.3)
reline (0.6.2)
reline (0.6.3)
io-console (~> 0.5)
request_store (1.7.0)
rack (>= 1.4)
@@ -713,22 +717,22 @@ GEM
rotp (6.3.0)
rouge (4.6.1)
rpam2 (4.0.2)
rqrcode (3.1.0)
rqrcode (3.1.1)
chunky_png (~> 1.0)
rqrcode_core (~> 2.0)
rqrcode_core (2.0.0)
rspec (3.13.1)
rqrcode_core (2.0.1)
rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.5)
rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-github (3.0.0)
rspec-core (~> 3.0)
rspec-mocks (3.13.5)
rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-rails (8.0.2)
@@ -745,7 +749,7 @@ GEM
rspec-mocks (~> 3.0)
sidekiq (>= 5, < 9)
rspec-support (3.13.6)
rubocop (1.81.6)
rubocop (1.81.7)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
@@ -756,7 +760,7 @@ GEM
rubocop-ast (>= 1.47.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.47.1)
rubocop-ast (1.48.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-capybara (2.22.1)
@@ -769,16 +773,16 @@ GEM
lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.47.1, < 2.0)
rubocop-rails (2.33.4)
rubocop-rails (2.34.2)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rspec (3.7.0)
rubocop-rspec (3.8.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec_rails (2.31.0)
rubocop (~> 1.81)
rubocop-rspec_rails (2.32.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
@@ -788,7 +792,7 @@ GEM
ruby-saml (1.18.1)
nokogiri (>= 1.13.10)
rexml
ruby-vips (2.2.5)
ruby-vips (2.3.0)
ffi (~> 1.12)
logger
rubyzip (3.2.2)
@@ -803,9 +807,9 @@ GEM
activerecord (>= 4.0.0)
railties (>= 4.0.0)
securerandom (0.4.1)
shoulda-matchers (6.5.0)
activesupport (>= 5.2.0)
sidekiq (8.0.9)
shoulda-matchers (7.0.1)
activesupport (>= 7.1)
sidekiq (8.0.10)
connection_pool (>= 2.5.0)
json (>= 2.9.0)
logger (>= 1.6.2)
@@ -816,7 +820,7 @@ GEM
sidekiq-scheduler (6.0.1)
rufus-scheduler (~> 3.2)
sidekiq (>= 7.3, < 9)
sidekiq-unique-jobs (8.0.11)
sidekiq-unique-jobs (8.0.12)
concurrent-ruby (~> 1.0, >= 1.0.5)
sidekiq (>= 7.0.0, < 9.0.0)
thor (>= 1.0, < 3.0)
@@ -835,9 +839,10 @@ GEM
stackprof (0.2.27)
starry (0.2.0)
base64
stoplight (5.4.0)
stoplight (5.7.0)
concurrent-ruby
zeitwerk
stringio (3.1.7)
stringio (3.1.9)
strong_migrations (2.5.1)
activerecord (>= 7.1)
swd (2.0.3)
@@ -851,10 +856,10 @@ GEM
unicode-display_width (>= 1.1.1, < 4)
terrapin (1.1.1)
climate_control
test-prof (1.4.4)
test-prof (1.5.0)
thor (1.4.0)
tilt (2.6.1)
timeout (0.4.3)
timeout (0.5.0)
tpm-key_attestation (0.14.1)
bindata (~> 2.4)
openssl (> 2.0)
@@ -875,7 +880,7 @@ GEM
unf (~> 0.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2025.2)
tzinfo-data (1.2025.3)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@@ -883,7 +888,7 @@ GEM
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
uri (1.0.4)
uri (1.1.1)
useragent (0.16.11)
validate_url (1.0.15)
activemodel (>= 3.0.0)
@@ -911,11 +916,11 @@ GEM
activesupport
faraday (~> 2.0)
faraday-follow_redirects
webmock (3.26.0)
webmock (3.26.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.9.1)
webrick (1.9.2)
websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0)
@@ -933,12 +938,12 @@ DEPENDENCIES
active_model_serializers (~> 0.10)
addressable (~> 2.8)
annotaterb (~> 4.13)
aws-sdk-core (< 3.216.0)
aws-sdk-core
aws-sdk-s3 (~> 1.123)
better_errors (~> 2.9)
binding_of_caller (~> 1.0)
blurhash (~> 0.1)
bootsnap (~> 1.18.0)
bootsnap (~> 1.19.0)
brakeman (~> 7.0)
browser
bundler-audit (~> 0.9)
@@ -1005,7 +1010,7 @@ DEPENDENCIES
oj (~> 3.14)
omniauth (~> 2.0)
omniauth-cas (~> 3.0.0.beta.1)
omniauth-rails_csrf_protection (~> 1.0)
omniauth-rails_csrf_protection (~> 2.0)
omniauth-saml (~> 2.0)
omniauth_openid_connect (~> 0.8.0)
opentelemetry-api (~> 1.7.0)
@@ -1018,7 +1023,7 @@ DEPENDENCIES
opentelemetry-instrumentation-http (~> 0.27.0)
opentelemetry-instrumentation-http_client (~> 0.26.0)
opentelemetry-instrumentation-net_http (~> 0.26.0)
opentelemetry-instrumentation-pg (~> 0.32.0)
opentelemetry-instrumentation-pg (~> 0.34.0)
opentelemetry-instrumentation-rack (~> 0.29.0)
opentelemetry-instrumentation-rails (~> 0.39.0)
opentelemetry-instrumentation-redis (~> 0.28.0)
@@ -1028,11 +1033,11 @@ DEPENDENCIES
parslet
pg (~> 1.5)
pghero
playwright-ruby-client (= 1.55.0)
playwright-ruby-client (= 1.57.0)
premailer-rails
prometheus_exporter (~> 2.2)
propshaft
public_suffix (~> 6.0)
public_suffix (~> 7.0)
puma (~> 7.0)
pundit (~> 2.3)
rack-attack (~> 6.6)
@@ -1085,7 +1090,7 @@ DEPENDENCIES
xorcist (~> 1.1)
RUBY VERSION
ruby 3.4.1p0
ruby 3.4.1p0
BUNDLED WITH
2.7.2
4.0.2

View File

@@ -18,4 +18,5 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
| 4.5.x | Yes |
| 4.4.x | Yes |
| 4.3.x | Until 2026-05-06 |
| < 4.3 | No |
| 4.2.x | Until 2026-01-08 |
| < 4.2 | No |

View File

@@ -4,31 +4,17 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature!, if: :authorized_fetch_mode?
before_action :check_authorization
before_action :set_items
before_action :set_size
before_action :set_type
def show
expires_in 3.minutes, public: public_fetch_mode?
if @unauthorized
render json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter
else
render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter
end
render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter
end
private
def check_authorization
# Because in public fetch mode we cache the response, there would be no
# benefit from performing the check below, since a blocked account or domain
# would likely be served the cache from the reverse proxy anyway
@unauthorized = authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
end
def set_items
case params[:id]
when 'featured'
@@ -71,7 +57,11 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
end
def for_signed_account
if @unauthorized
# Because in public fetch mode we cache the response, there would be no
# benefit from performing the check below, since a blocked account or domain
# would likely be served the cache from the reverse proxy anyway
if authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
[]
else
yield

View File

@@ -36,8 +36,9 @@ class ActivityPub::ContextsController < ActivityPub::BaseController
def context_presenter
first_page = ActivityPub::CollectionPresenter.new(
id: items_context_url(@conversation, page_params),
type: :unordered,
part_of: context_url(@conversation),
part_of: items_context_url(@conversation),
next: next_page,
items: @items.map { |status| status.local? ? ActivityPub::TagManager.instance.uri_for(status) : status.uri }
)
@@ -51,7 +52,7 @@ class ActivityPub::ContextsController < ActivityPub::BaseController
page = ActivityPub::CollectionPresenter.new(
id: items_context_url(@conversation, page_params),
type: :unordered,
part_of: context_url(@conversation),
part_of: items_context_url(@conversation),
next: next_page,
items: @items.map { |status| status.local? ? ActivityPub::TagManager.instance.uri_for(status) : status.uri }
)

View File

@@ -3,7 +3,6 @@
class ActivityPub::InboxesController < ActivityPub::BaseController
include JsonLdHelper
before_action :skip_large_payload
before_action :skip_unknown_actor_activity
before_action :require_actor_signature!
skip_before_action :authenticate_user!
@@ -17,10 +16,6 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
private
def skip_large_payload
head 413 if request.content_length > ActivityPub::Activity::MAX_JSON_SIZE
end
def skip_unknown_actor_activity
head 202 if unknown_affected_account?
end
@@ -44,7 +39,7 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
return @body if defined?(@body)
@body = request.body.read
@body.force_encoding('UTF-8') if @body.present?
@body.presence&.force_encoding('UTF-8')
request.body.rewind if request.body.respond_to?(:rewind)

View File

@@ -5,6 +5,15 @@ module Admin
def index
authorize :custom_emoji, :index?
# If filtering by local emojis, remove by_domain filter.
params.delete(:by_domain) if params[:local].present?
# If filtering by domain, ensure remote filter is set.
if params[:by_domain].present?
params.delete(:local)
params[:remote] = '1'
end
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
@form = Form::CustomEmojiBatch.new
end

View File

@@ -9,7 +9,7 @@ module Admin
@site_upload.destroy!
redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
redirect_back_or_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
end
private

View File

@@ -1,10 +1,12 @@
# frozen_string_literal: true
class Api::V1::AnnualReportsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, except: :index
include AsyncRefreshesConcern
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:read, :generate]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:read, :generate]
before_action :require_user!
before_action :set_annual_report, except: :index
before_action :set_annual_report, only: [:show, :read]
def index
with_read_replica do
@@ -28,6 +30,28 @@ class Api::V1::AnnualReportsController < Api::BaseController
relationships: @relationships
end
def state
render json: { state: report_state }
end
def generate
return render_empty unless year == AnnualReport.current_campaign
return render_empty if GeneratedAnnualReport.exists?(account_id: current_account.id, year: year)
async_refresh = AsyncRefresh.new(refresh_key)
if async_refresh.running?
add_async_refresh_header(async_refresh, retry_seconds: 2)
return head 202
end
add_async_refresh_header(AsyncRefresh.create(refresh_key), retry_seconds: 2)
GenerateAnnualReportWorker.perform_async(current_account.id, year)
head 202
end
def read
@annual_report.view!
render_empty
@@ -35,7 +59,21 @@ class Api::V1::AnnualReportsController < Api::BaseController
private
def report_state
AnnualReport.new(current_account, year).state do |async_refresh|
add_async_refresh_header(async_refresh, retry_seconds: 2)
end
end
def refresh_key
"wrapstodon:#{current_account.id}:#{year}"
end
def year
params[:id]&.to_i
end
def set_annual_report
@annual_report = GeneratedAnnualReport.find_by!(account_id: current_account.id, year: params[:id])
@annual_report = GeneratedAnnualReport.find_by!(account_id: current_account.id, year: year)
end
end

View File

@@ -41,8 +41,8 @@ class Api::V1::Statuses::QuotesController < Api::V1::Statuses::BaseController
if current_account&.id != @status.account_id
domains = @statuses.filter_map(&:account_domain).uniq
account_ids = @statuses.map(&:account_id).uniq
relations = current_account&.relations_map(account_ids, domains) || {}
@statuses.reject! { |status| StatusFilter.new(status, current_account, relations).filtered? }
current_account&.preload_relations!(account_ids, domains)
@statuses.reject! { |status| StatusFilter.new(status, current_account).filtered? }
end
end

View File

@@ -107,7 +107,9 @@ class Api::V1::StatusesController < Api::BaseController
@status = Status.where(account: current_account).find(params[:id])
authorize @status, :update?
update_options = {
UpdateStatusService.new.call(
@status,
current_account.id,
text: status_params[:status],
media_ids: status_params[:media_ids],
media_attributes: status_params[:media_attributes],
@@ -115,12 +117,9 @@ class Api::V1::StatusesController < Api::BaseController
language: status_params[:language],
spoiler_text: status_params[:spoiler_text],
poll: status_params[:poll],
content_type: status_params[:content_type],
}
update_options[:quote_approval_policy] = quote_approval_policy if status_params[:quote_approval_policy].present?
UpdateStatusService.new.call(@status, current_account.id, update_options)
quote_approval_policy: quote_approval_policy,
content_type: status_params[:content_type]
)
render json: @status, serializer: REST::StatusSerializer
end
@@ -129,10 +128,11 @@ class Api::V1::StatusesController < Api::BaseController
@status = Status.where(account: current_account).find(params[:id])
authorize @status, :destroy?
json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true
@status.discard_with_reblogs
StatusPin.find_by(status: @status)&.destroy
@status.account.statuses_count = @status.account.statuses_count - 1
json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true
RemovalWorker.perform_async(@status.id, { 'redraft' => !truthy_param?(:delete_media) })

View File

@@ -0,0 +1,54 @@
# frozen_string_literal: true
class Api::V1Alpha::CollectionItemsController < Api::BaseController
include Authorization
before_action :check_feature_enabled
before_action -> { doorkeeper_authorize! :write, :'write:collections' }
before_action :require_user!
before_action :set_collection
before_action :set_account, only: [:create]
before_action :set_collection_item, only: [:destroy]
after_action :verify_authorized
def create
authorize @collection, :update?
authorize @account, :feature?
@item = AddAccountToCollectionService.new.call(@collection, @account)
render json: @item, serializer: REST::CollectionItemSerializer
end
def destroy
authorize @collection, :update?
@collection_item.destroy
head 200
end
private
def set_collection
@collection = Collection.find(params[:collection_id])
end
def set_account
return render(json: { error: '`account_id` parameter is missing' }, status: 422) if params[:account_id].blank?
@account = Account.find(params[:account_id])
end
def set_collection_item
@collection_item = @collection.collection_items.find(params[:id])
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end

View File

@@ -0,0 +1,114 @@
# frozen_string_literal: true
class Api::V1Alpha::CollectionsController < Api::BaseController
include Authorization
DEFAULT_COLLECTIONS_LIMIT = 40
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: ValidationErrorFormatter.new(e).as_json }, status: 422
end
before_action :check_feature_enabled
before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write, :'write:collections' }, only: [:create, :update, :destroy]
before_action :require_user!, only: [:create, :update, :destroy]
before_action :set_account, only: [:index]
before_action :set_collections, only: [:index]
before_action :set_collection, only: [:show, :update, :destroy]
after_action :insert_pagination_headers, only: [:index]
after_action :verify_authorized
def index
cache_if_unauthenticated!
authorize Collection, :index?
render json: @collections, each_serializer: REST::BaseCollectionSerializer
end
def show
cache_if_unauthenticated!
authorize @collection, :show?
render json: @collection, serializer: REST::CollectionSerializer
end
def create
authorize Collection, :create?
@collection = CreateCollectionService.new.call(collection_creation_params, current_user.account)
render json: @collection, serializer: REST::CollectionSerializer
end
def update
authorize @collection, :update?
@collection.update!(collection_update_params) # TODO: Create a service for this to federate changes
render json: @collection, serializer: REST::CollectionSerializer
end
def destroy
authorize @collection, :destroy?
@collection.destroy
head 200
end
private
def set_account
@account = Account.find(params[:account_id])
end
def set_collections
@collections = @account.collections
.with_tag
.order(created_at: :desc)
.offset(offset_param)
.limit(limit_param(DEFAULT_COLLECTIONS_LIMIT))
end
def set_collection
@collection = Collection.find(params[:id])
end
def collection_creation_params
params.permit(:name, :description, :sensitive, :discoverable, :tag_name, account_ids: [])
end
def collection_update_params
params.permit(:name, :description, :sensitive, :discoverable, :tag_name)
end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
def next_path
return unless records_continue?
api_v1_alpha_account_collections_url(@account, pagination_params(offset: offset_param + limit_param(DEFAULT_COLLECTIONS_LIMIT)))
end
def prev_path
return if offset_param.zero?
api_v1_alpha_account_collections_url(@account, pagination_params(offset: offset_param - limit_param(DEFAULT_COLLECTIONS_LIMIT)))
end
def records_continue?
((offset_param * limit_param(DEFAULT_COLLECTIONS_LIMIT)) + @collections.size) < @account.collections.size
end
def offset_param
params[:offset].to_i
end
end

View File

@@ -62,7 +62,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
end
def set_push_subscription
@push_subscription = ::Web::PushSubscription.where(user_id: active_session.user_id).find(params[:id])
@push_subscription = ::Web::PushSubscription.find(params[:id])
end
def subscription_params

View File

@@ -135,7 +135,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
@accept_token = session[:accept_token] = SecureRandom.hex
@invite_code = invite_code
set_locale { render :rules }
render :rules
end
def is_flashing_format? # rubocop:disable Naming/PredicatePrefix

View File

@@ -6,9 +6,9 @@ module Api::InteractionPoliciesConcern
def quote_approval_policy
case status_params[:quote_approval_policy].presence || current_user.setting_default_quote_policy
when 'public'
Status::QUOTE_APPROVAL_POLICY_FLAGS[:public] << 16
InteractionPolicy::POLICY_FLAGS[:public] << 16
when 'followers'
Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers] << 16
InteractionPolicy::POLICY_FLAGS[:followers] << 16
when 'nobody'
0
else

View File

@@ -19,7 +19,7 @@ module CacheConcern
# from being used as cache keys, while allowing to `Vary` on them (to not serve
# anonymous cached data to authenticated requests when authentication matters)
def enforce_cache_control!
vary = response.headers['Vary'].to_s.split(',').map { |x| x.strip.downcase }.reject(&:empty?)
vary = response.headers['Vary']&.split&.map { |x| x.strip.downcase }
return unless vary.present? && %w(cookie authorization signature).any? { |header| vary.include?(header) && request.headers[header].present? }
response.cache_control.replace(private: true, no_store: true)

View File

@@ -7,6 +7,7 @@ class FollowerAccountsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? }
before_action :protect_hidden_collections, if: -> { request.format.json? }
skip_around_action :set_locale, if: -> { request.format == :json }
skip_before_action :require_functional!, unless: :limited_federation_mode?
@@ -18,8 +19,6 @@ class FollowerAccountsController < ApplicationController
end
format.json do
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
render json: collection_presenter,
@@ -41,6 +40,10 @@ class FollowerAccountsController < ApplicationController
@follows = scope.recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
end
def protect_hidden_collections
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
end
def page_requested?
params[:page].present?
end

View File

@@ -7,6 +7,7 @@ class FollowingAccountsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? }
before_action :protect_hidden_collections, if: -> { request.format.json? }
skip_around_action :set_locale, if: -> { request.format == :json }
skip_before_action :require_functional!, unless: :limited_federation_mode?
@@ -18,11 +19,6 @@ class FollowingAccountsController < ApplicationController
end
format.json do
if page_requested? && @account.hide_collections?
forbidden
next
end
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
render json: collection_presenter,
@@ -44,6 +40,10 @@ class FollowingAccountsController < ApplicationController
@follows = scope.recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
end
def protect_hidden_collections
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
end
def page_requested?
params[:page].present?
end

View File

@@ -26,7 +26,7 @@ class SeveredRelationshipsController < ApplicationController
private
def set_event
@event = AccountRelationshipSeveranceEvent.where(account: current_account).find(params[:id])
@event = AccountRelationshipSeveranceEvent.find(params[:id])
end
def following_data

View File

@@ -29,7 +29,7 @@ class StatusesController < ApplicationController
end
format.json do
expires_in @status.quote&.pending? ? 5.seconds : 3.minutes, public: true if @status.distributable? && public_fetch_mode?
expires_in 3.minutes, public: true if @status.distributable? && public_fetch_mode?
render_with_cache json: @status, content_type: 'application/activity+json', serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter
end
end

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
class WrapstodonController < ApplicationController
include WebAppControllerConcern
include Authorization
include AccountOwnedConcern
vary_by 'Accept, Accept-Language, Cookie'
before_action :set_generated_annual_report
skip_before_action :require_functional!, only: :show, unless: :limited_federation_mode?
def show
expires_in 10.minutes, public: true if current_account.nil?
end
private
def set_generated_annual_report
@generated_annual_report = GeneratedAnnualReport.find_by!(account: @account, year: params[:year], share_key: params[:share_key])
end
end

View File

@@ -153,11 +153,9 @@ module ApplicationHelper
tag.meta(content: content, property: property)
end
def body_classes
def html_classes
output = []
output << content_for(:body_classes)
output << "flavour-#{current_flavour.parameterize}"
output << "skin-#{current_skin.parameterize}"
output << content_for(:html_classes)
output << 'system-font' if current_account&.user&.setting_system_font_ui
output << 'custom-scrollbars' unless current_account&.user&.setting_system_scrollbars_ui
output << (current_account&.user&.setting_reduce_motion ? 'reduce-motion' : 'no-reduce-motion')
@@ -165,6 +163,12 @@ module ApplicationHelper
output.compact_blank.join(' ')
end
def body_classes
output = []
output << content_for(:body_classes)
output.compact_blank.join(' ')
end
def cdn_host
Rails.configuration.action_controller.asset_host
end

View File

@@ -2,7 +2,7 @@
module DatabaseHelper
def replica_enabled?
ENV['REPLICA_DB_NAME'] || ENV.fetch('REPLICA_DATABASE_URL', nil)
ENV['REPLICA_DB_NAME'] || ENV['REPLICA_DB_HOST'] || ENV.fetch('REPLICA_DATABASE_URL', nil)
end
module_function :replica_enabled?

View File

@@ -1,6 +1,8 @@
# frozen_string_literal: true
module FiltersHelper
KEYWORDS_LIMIT = 5
def filter_action_label(action)
safe_join(
[
@@ -9,4 +11,10 @@ module FiltersHelper
]
)
end
def filter_keywords(filter)
filter.keywords.map(&:keyword).take(KEYWORDS_LIMIT).tap do |list|
list << '…' if filter.keywords.size > KEYWORDS_LIMIT
end.join(', ')
end
end

View File

@@ -35,7 +35,7 @@ module LanguagesHelper
cy: ['Welsh', 'Cymraeg'].freeze,
da: ['Danish', 'dansk'].freeze,
de: ['German', 'Deutsch'].freeze,
dv: ['Divehi', 'Dhivehi'].freeze,
dv: ['Divehi', 'ދިވެހި'].freeze,
dz: ['Dzongkha', 'རྫོང་ཁ'].freeze,
ee: ['Ewe', 'Eʋegbe'].freeze,
el: ['Greek', 'Ελληνικά'].freeze,
@@ -100,7 +100,7 @@ module LanguagesHelper
lo: ['Lao', 'ລາວ'].freeze,
lt: ['Lithuanian', 'lietuvių kalba'].freeze,
lu: ['Luba-Katanga', 'Tshiluba'].freeze,
lv: ['Latvian', 'latviešu valoda'].freeze,
lv: ['Latvian', 'Latviski'].freeze,
mg: ['Malagasy', 'fiteny malagasy'].freeze,
mh: ['Marshallese', 'Kajin M̧ajeļ'].freeze,
mi: ['Māori', 'te reo Māori'].freeze,

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module WrapstodonHelper
def render_wrapstodon_share_data(report)
payload = ActiveModelSerializers::SerializableResource.new(
AnnualReportsPresenter.new([report]),
serializer: REST::AnnualReportsSerializer,
scope: nil,
scope_name: :current_user
).as_json
payload[:me] = current_account.id.to_s if user_signed_in?
payload[:domain] = Addressable::IDNA.to_unicode(Rails.configuration.x.local_domain)
json_string = payload.to_json
# rubocop:disable Rails/OutputSafety
content_tag(:script, json_escape(json_string).html_safe, type: 'application/json', id: 'wrapstodon-data')
# rubocop:enable Rails/OutputSafety
end
end

View File

@@ -1,31 +1,49 @@
# frozen_string_literal: true
class DateOfBirthInput < SimpleForm::Inputs::Base
OPTIONS = [
{ autocomplete: 'bday-day', maxlength: 2, pattern: '[0-9]+', placeholder: 'DD' }.freeze,
{ autocomplete: 'bday-month', maxlength: 2, pattern: '[0-9]+', placeholder: 'MM' }.freeze,
{ autocomplete: 'bday-year', maxlength: 4, pattern: '[0-9]+', placeholder: 'YYYY' }.freeze,
].freeze
OPTIONS = {
day: { autocomplete: 'bday-day', maxlength: 2, pattern: '[0-9]+', placeholder: 'DD' },
month: { autocomplete: 'bday-month', maxlength: 2, pattern: '[0-9]+', placeholder: 'MM' },
year: { autocomplete: 'bday-year', maxlength: 4, pattern: '[0-9]+', placeholder: 'YYYY' },
}.freeze
def input(wrapper_options = nil)
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
merged_input_options[:inputmode] = 'numeric'
values = (object.public_send(attribute_name) || '').split('.')
safe_join(Array.new(3) do |index|
options = merged_input_options.merge(OPTIONS[index]).merge id: generate_id(index), 'aria-label': I18n.t("simple_form.labels.user.date_of_birth_#{index + 1}i"), value: values[index]
@builder.text_field("#{attribute_name}(#{index + 1}i)", options)
end)
safe_join(
ordered_options.map do |option|
options = merged_input_options
.merge(OPTIONS[option])
.merge(
id: generate_id(option),
'aria-label': I18n.t("simple_form.labels.user.date_of_birth_#{param_for(option)}"),
value: values[option]
)
@builder.text_field("#{attribute_name}(#{param_for(option)})", options)
end
)
end
def label_target
"#{attribute_name}_1i"
"#{attribute_name}_#{param_for(ordered_options.first)}"
end
private
def generate_id(index)
"#{object_name}_#{attribute_name}_#{index + 1}i"
def ordered_options
I18n.t('date.order').map(&:to_sym)
end
def generate_id(option)
"#{object_name}_#{attribute_name}_#{param_for(option)}"
end
def param_for(option)
"#{ActionView::Helpers::DateTimeSelector::POSITION[option]}i"
end
def values
Date._parse((object.public_send(attribute_name) || '').to_s).transform_keys(mon: :month, mday: :day)
end
end

View File

@@ -1,7 +1,7 @@
import { createRoot } from 'react-dom/client';
import Rails from '@rails/ujs';
import { decode, ValidationError } from 'blurhash';
import { on } from 'delegated-events';
import ready from '../mastodon/ready';
@@ -24,10 +24,9 @@ const setAnnouncementEndsAttributes = (target: HTMLInputElement) => {
}
};
Rails.delegate(
document,
'input[type="datetime-local"]#announcement_starts_at',
on(
'change',
'input[type="datetime-local"]#announcement_starts_at',
({ target }) => {
if (target instanceof HTMLInputElement)
setAnnouncementEndsAttributes(target);
@@ -63,7 +62,7 @@ const hideSelectAll = () => {
if (hiddenField) hiddenField.value = '0';
};
Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
on('change', '#batch_checkbox_all', ({ target }) => {
if (!(target instanceof HTMLInputElement)) return;
const selectAllMatchingElement = document.querySelector(
@@ -85,7 +84,7 @@ Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
}
});
Rails.delegate(document, '.batch-table__select-all button', 'click', () => {
on('click', '.batch-table__select-all button', () => {
const hiddenField = document.querySelector<HTMLInputElement>(
'#select_all_matching',
);
@@ -113,7 +112,7 @@ Rails.delegate(document, '.batch-table__select-all button', 'click', () => {
}
});
Rails.delegate(document, batchCheckboxClassName, 'change', () => {
on('change', batchCheckboxClassName, () => {
const checkAllElement = document.querySelector<HTMLInputElement>(
'input#batch_checkbox_all',
);
@@ -140,14 +139,9 @@ Rails.delegate(document, batchCheckboxClassName, 'change', () => {
}
});
Rails.delegate(
document,
'.filter-subset--with-select select',
'change',
({ target }) => {
if (target instanceof HTMLSelectElement) target.form?.submit();
},
);
on('change', '.filter-subset--with-select select', ({ target }) => {
if (target instanceof HTMLSelectElement) target.form?.submit();
});
const onDomainBlockSeverityChange = (target: HTMLSelectElement) => {
const rejectMediaDiv = document.querySelector(
@@ -168,11 +162,11 @@ const onDomainBlockSeverityChange = (target: HTMLSelectElement) => {
}
};
Rails.delegate(document, '#domain_block_severity', 'change', ({ target }) => {
on('change', '#domain_block_severity', ({ target }) => {
if (target instanceof HTMLSelectElement) onDomainBlockSeverityChange(target);
});
const onEnableBootstrapTimelineAccountsChange = (target: HTMLInputElement) => {
function onEnableBootstrapTimelineAccountsChange(target: HTMLInputElement) {
const bootstrapTimelineAccountsField =
document.querySelector<HTMLInputElement>(
'#form_admin_settings_bootstrap_timeline_accounts',
@@ -194,12 +188,11 @@ const onEnableBootstrapTimelineAccountsChange = (target: HTMLInputElement) => {
);
}
}
};
}
Rails.delegate(
document,
'#form_admin_settings_enable_bootstrap_timeline_accounts',
on(
'change',
'#form_admin_settings_enable_bootstrap_timeline_accounts',
({ target }) => {
if (target instanceof HTMLInputElement)
onEnableBootstrapTimelineAccountsChange(target);
@@ -239,11 +232,11 @@ const onChangeRegistrationMode = (target: HTMLSelectElement) => {
});
};
const convertUTCDateTimeToLocal = (value: string) => {
function convertUTCDateTimeToLocal(value: string) {
const date = new Date(value + 'Z');
const twoChars = (x: number) => x.toString().padStart(2, '0');
return `${date.getFullYear()}-${twoChars(date.getMonth() + 1)}-${twoChars(date.getDate())}T${twoChars(date.getHours())}:${twoChars(date.getMinutes())}`;
};
}
function convertLocalDatetimeToUTC(value: string) {
const date = new Date(value);
@@ -251,14 +244,9 @@ function convertLocalDatetimeToUTC(value: string) {
return fullISO8601.slice(0, fullISO8601.indexOf('T') + 6);
}
Rails.delegate(
document,
'#form_admin_settings_registrations_mode',
'change',
({ target }) => {
if (target instanceof HTMLSelectElement) onChangeRegistrationMode(target);
},
);
on('change', '#form_admin_settings_registrations_mode', ({ target }) => {
if (target instanceof HTMLSelectElement) onChangeRegistrationMode(target);
});
async function mountReactComponent(element: Element) {
const componentName = element.getAttribute('data-admin-component');
@@ -268,9 +256,8 @@ async function mountReactComponent(element: Element) {
const componentProps = JSON.parse(stringProps) as object;
const { default: AdminComponent } = await import(
'@/mastodon/containers/admin_component'
);
const { default: AdminComponent } =
await import('@/mastodon/containers/admin_component');
const { default: Component } = (await import(
`@/mastodon/components/admin/${componentName}.jsx`
@@ -305,7 +292,7 @@ ready(() => {
if (registrationMode) onChangeRegistrationMode(registrationMode);
const checkAllElement = document.querySelector<HTMLInputElement>(
'input#batch_checkbox_all',
'#batch_checkbox_all',
);
if (checkAllElement) {
const allCheckboxes = Array.from(
@@ -318,7 +305,7 @@ ready(() => {
}
document
.querySelector('a#add-instance-button')
.querySelector<HTMLAnchorElement>('a#add-instance-button')
?.addEventListener('click', (e) => {
const domain = document.querySelector<HTMLInputElement>(
'input[type="text"]#by_domain',
@@ -342,7 +329,7 @@ ready(() => {
}
});
Rails.delegate(document, 'form', 'submit', ({ target }) => {
on('submit', 'form', ({ target }) => {
if (target instanceof HTMLFormElement)
target
.querySelectorAll<HTMLInputElement>('input[type="datetime-local"]')

View File

@@ -4,8 +4,8 @@ import { IntlMessageFormat } from 'intl-messageformat';
import type { MessageDescriptor, PrimitiveType } from 'react-intl';
import { defineMessages } from 'react-intl';
import Rails from '@rails/ujs';
import axios from 'axios';
import { on } from 'delegated-events';
import { throttle } from 'lodash';
import { timeAgoString } from '../mastodon/components/relative_timestamp';
@@ -175,10 +175,9 @@ function loaded() {
});
}
Rails.delegate(
document,
'input#user_account_attributes_username',
on(
'input',
'input#user_account_attributes_username',
throttle(
({ target }) => {
if (!(target instanceof HTMLInputElement)) return;
@@ -202,60 +201,47 @@ function loaded() {
),
);
Rails.delegate(
document,
'#user_password,#user_password_confirmation',
'input',
() => {
const password = document.querySelector<HTMLInputElement>(
'input#user_password',
);
const confirmation = document.querySelector<HTMLInputElement>(
'input#user_password_confirmation',
);
if (!confirmation || !password) return;
on('input', '#user_password,#user_password_confirmation', () => {
const password = document.querySelector<HTMLInputElement>(
'input#user_password',
);
const confirmation = document.querySelector<HTMLInputElement>(
'input#user_password_confirmation',
);
if (!confirmation || !password) return;
if (
confirmation.value &&
confirmation.value.length > password.maxLength
) {
confirmation.setCustomValidity(
formatMessage(messages.passwordExceedsLength),
);
} else if (password.value && password.value !== confirmation.value) {
confirmation.setCustomValidity(
formatMessage(messages.passwordDoesNotMatch),
);
} else {
confirmation.setCustomValidity('');
}
},
);
if (confirmation.value && confirmation.value.length > password.maxLength) {
confirmation.setCustomValidity(
formatMessage(messages.passwordExceedsLength),
);
} else if (password.value && password.value !== confirmation.value) {
confirmation.setCustomValidity(
formatMessage(messages.passwordDoesNotMatch),
);
} else {
confirmation.setCustomValidity('');
}
});
}
Rails.delegate(
document,
'#edit_profile input[type=file]',
'change',
({ target }) => {
if (!(target instanceof HTMLInputElement)) return;
on('change', '#edit_profile input[type=file]', ({ target }) => {
if (!(target instanceof HTMLInputElement)) return;
const avatar = document.querySelector<HTMLImageElement>(
`img#${target.id}-preview`,
);
const avatar = document.querySelector<HTMLImageElement>(
`img#${target.id}-preview`,
);
if (!avatar) return;
if (!avatar) return;
let file: File | undefined;
if (target.files) file = target.files[0];
let file: File | undefined;
if (target.files) file = target.files[0];
const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
if (url) avatar.src = url;
},
);
if (url) avatar.src = url;
});
Rails.delegate(document, '.input-copy input', 'click', ({ target }) => {
on('click', '.input-copy input', ({ target }) => {
if (!(target instanceof HTMLInputElement)) return;
target.focus();
@@ -263,7 +249,7 @@ Rails.delegate(document, '.input-copy input', 'click', ({ target }) => {
target.setSelectionRange(0, target.value.length);
});
Rails.delegate(document, '.input-copy button', 'click', ({ target }) => {
on('click', '.input-copy button', ({ target }) => {
if (!(target instanceof HTMLButtonElement)) return;
const input = target.parentNode?.querySelector<HTMLInputElement>(
@@ -312,22 +298,22 @@ const toggleSidebar = () => {
sidebar.classList.toggle('visible');
};
Rails.delegate(document, '.sidebar__toggle__icon', 'click', () => {
on('click', '.sidebar__toggle__icon', () => {
toggleSidebar();
});
Rails.delegate(document, '.sidebar__toggle__icon', 'keydown', (e) => {
on('keydown', '.sidebar__toggle__icon', (e) => {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
toggleSidebar();
}
});
Rails.delegate(document, 'img.custom-emoji', 'mouseover', ({ target }) => {
on('mouseover', 'img.custom-emoji', ({ target }) => {
if (target instanceof HTMLImageElement && target.dataset.original)
target.src = target.dataset.original;
});
Rails.delegate(document, 'img.custom-emoji', 'mouseout', ({ target }) => {
on('mouseout', 'img.custom-emoji', ({ target }) => {
if (target instanceof HTMLImageElement && target.dataset.static)
target.src = target.dataset.static;
});
@@ -376,22 +362,17 @@ const setInputHint = (
}
};
Rails.delegate(
document,
'#account_statuses_cleanup_policy_enabled',
'change',
({ target }) => {
if (!(target instanceof HTMLInputElement) || !target.form) return;
on('change', '#account_statuses_cleanup_policy_enabled', ({ target }) => {
if (!(target instanceof HTMLInputElement) || !target.form) return;
target.form
.querySelectorAll<
HTMLInputElement | HTMLSelectElement
>('input:not([type=hidden], #account_statuses_cleanup_policy_enabled), select')
.forEach((input) => {
setInputDisabled(input, !target.checked);
});
},
);
target.form
.querySelectorAll<
HTMLInputElement | HTMLSelectElement
>('input:not([type=hidden], #account_statuses_cleanup_policy_enabled), select')
.forEach((input) => {
setInputDisabled(input, !target.checked);
});
});
const updateDefaultQuotePrivacyFromPrivacy = (
privacySelect: EventTarget | null,
@@ -414,18 +395,13 @@ const updateDefaultQuotePrivacyFromPrivacy = (
}
};
Rails.delegate(
document,
'#user_settings_attributes_default_privacy',
'change',
({ target }) => {
updateDefaultQuotePrivacyFromPrivacy(target);
},
);
on('change', '#user_settings_attributes_default_privacy', ({ target }) => {
updateDefaultQuotePrivacyFromPrivacy(target);
});
// Empty the honeypot fields in JS in case something like an extension
// automatically filled them.
Rails.delegate(document, '#registration_new_user,#new_user', 'submit', () => {
on('submit', '#registration_new_user,#new_user', () => {
[
'user_website',
'user_confirm_password',
@@ -439,7 +415,7 @@ Rails.delegate(document, '#registration_new_user,#new_user', 'submit', () => {
});
});
Rails.delegate(document, '.rules-list button', 'click', ({ target }) => {
on('click', '.rules-list button', ({ target }) => {
if (!(target instanceof HTMLElement)) {
return;
}

View File

@@ -0,0 +1,67 @@
import { createRoot } from 'react-dom/client';
import { Provider as ReduxProvider } from 'react-redux';
import { importFetchedStatuses } from '@/mastodon/actions/importer';
import { hydrateStore } from '@/mastodon/actions/store';
import type { ApiAnnualReportResponse } from '@/mastodon/api/annual_report';
import { Router } from '@/mastodon/components/router';
import { WrapstodonSharedPage } from '@/mastodon/features/annual_report/shared_page';
import { IntlProvider, loadLocale } from '@/mastodon/locales';
import { loadPolyfills } from '@/mastodon/polyfills';
import ready from '@/mastodon/ready';
import { setReport } from '@/mastodon/reducers/slices/annual_report';
import { store } from '@/mastodon/store';
function loaded() {
const mountNode = document.getElementById('wrapstodon');
if (!mountNode) {
throw new Error('Mount node not found');
}
const propsNode = document.getElementById('wrapstodon-data');
if (!propsNode) {
throw new Error('Initial state prop not found');
}
const initialState = JSON.parse(
propsNode.textContent,
) as ApiAnnualReportResponse & { me?: string; domain: string };
const report = initialState.annual_reports[0];
if (!report) {
throw new Error('Initial state report not found');
}
// Set up store
store.dispatch(
hydrateStore({
meta: {
locale: document.documentElement.lang,
me: initialState.me,
domain: initialState.domain,
},
accounts: initialState.accounts,
}),
);
store.dispatch(importFetchedStatuses(initialState.statuses));
store.dispatch(setReport(report));
const root = createRoot(mountNode);
root.render(
<IntlProvider>
<ReduxProvider store={store}>
<Router>
<WrapstodonSharedPage />
</Router>
</ReduxProvider>
</IntlProvider>,
);
}
loadPolyfills()
.then(loadLocale)
.then(() => ready(loaded))
.catch((err: unknown) => {
console.error(err);
});

View File

@@ -1,25 +0,0 @@
export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST';
export const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS';
export const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL';
export function fetchBundleRequest(skipLoading) {
return {
type: BUNDLE_FETCH_REQUEST,
skipLoading,
};
}
export function fetchBundleSuccess(skipLoading) {
return {
type: BUNDLE_FETCH_SUCCESS,
skipLoading,
};
}
export function fetchBundleFail(error, skipLoading) {
return {
type: BUNDLE_FETCH_FAIL,
error,
skipLoading,
};
}

View File

@@ -0,0 +1,22 @@
import type { ApiCustomEmojiJSON } from '@/flavours/glitch/api_types/custom_emoji';
import { loadCustomEmoji } from '@/flavours/glitch/features/emoji';
export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) {
if (emojis.length === 0) {
return;
}
// First, check if we already have them all.
const { searchCustomEmojisByShortcodes, clearEtag } =
await import('@/flavours/glitch/features/emoji/database');
const existingEmojis = await searchCustomEmojisByShortcodes(
emojis.map((emoji) => emoji.shortcode),
);
// If there's a mismatch, re-import all custom emojis.
if (existingEmojis.length < emojis.length) {
await clearEtag('custom');
await loadCustomEmoji();
}
}

View File

@@ -1,6 +1,7 @@
import { createPollFromServerJSON } from 'flavours/glitch/models/poll';
import { importAccounts } from './accounts';
import { importCustomEmoji } from './emoji';
import { normalizeStatus } from './normalizer';
import { importPolls } from './polls';
@@ -39,6 +40,10 @@ export function importFetchedAccounts(accounts) {
if (account.moved) {
processAccount(account.moved);
}
if (account.emojis && account.username === account.acct) {
importCustomEmoji(account.emojis);
}
}
accounts.forEach(processAccount);
@@ -80,6 +85,10 @@ export function importFetchedStatuses(statuses, options = {}) {
if (status.card) {
status.card.authors.forEach(author => author.account && pushUnique(accounts, author.account));
}
if (status.emojis && status.account.username === status.account.acct) {
importCustomEmoji(status.emojis);
}
}
statuses.forEach(processStatus);

View File

@@ -2,6 +2,8 @@ import escapeTextContentForBrowser from 'escape-html';
import { autoHideCW } from '../../utils/content_warning';
import { importCustomEmoji } from './emoji';
const domParser = new DOMParser();
export function searchTextFromRawStatus (status) {
@@ -143,5 +145,9 @@ export function normalizeAnnouncement(announcement) {
normalAnnouncement.contentHtml = normalAnnouncement.content;
if (normalAnnouncement.emojis) {
importCustomEmoji(normalAnnouncement.emojis);
}
return normalAnnouncement;
}

View File

@@ -147,7 +147,7 @@ export const hydrateSearch = createAppAsyncThunk(
'search/hydrate',
(_args, { dispatch, getState }) => {
const me = getState().meta.get('me') as string;
const history = searchHistory.get(me) as RecentSearch[] | null;
const history = searchHistory.get(me);
if (history !== null) {
dispatch(updateSearchHistory(history));

View File

@@ -37,7 +37,9 @@ export function hydrateStore(rawState) {
dispatch(hydrateCompose());
dispatch(hydrateSearch());
dispatch(importFetchedAccounts(Object.values(rawState.accounts)));
if (rawState.accounts) {
dispatch(importFetchedAccounts(Object.values(rawState.accounts)));
}
dispatch(saveSettings());
};
}

View File

@@ -7,7 +7,7 @@ import { toServerSideType } from 'flavours/glitch/utils/filters';
import { importFetchedStatus, importFetchedStatuses } from './importer';
import { submitMarkers } from './markers';
import {timelineDelete} from './timelines_typed';
import { timelineDelete } from './timelines_typed';
export { disconnectTimeline } from './timelines_typed';
@@ -25,9 +25,15 @@ export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
export const TIMELINE_MARK_AS_PARTIAL = 'TIMELINE_MARK_AS_PARTIAL';
export const TIMELINE_INSERT = 'TIMELINE_INSERT';
// When adding new special markers here, make sure to update TIMELINE_NON_STATUS_MARKERS in actions/timelines_typed.js
export const TIMELINE_SUGGESTIONS = 'inline-follow-suggestions';
export const TIMELINE_GAP = null;
export const TIMELINE_NON_STATUS_MARKERS = [
TIMELINE_GAP,
TIMELINE_SUGGESTIONS,
];
export const loadPending = timeline => ({
type: TIMELINE_LOAD_PENDING,
timeline,

View File

@@ -2,6 +2,12 @@ import { createAction } from '@reduxjs/toolkit';
import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
import { TIMELINE_NON_STATUS_MARKERS } from './timelines';
export function isNonStatusId(value: unknown) {
return TIMELINE_NON_STATUS_MARKERS.includes(value as string | null);
}
export const disconnectTimeline = createAction(
'timeline/disconnect',
({ timeline }: { timeline: string }) => ({

View File

@@ -0,0 +1,38 @@
import api, { apiRequestGet, getAsyncRefreshHeader } from '../api';
import type { ApiAccountJSON } from '../api_types/accounts';
import type { ApiStatusJSON } from '../api_types/statuses';
import type { AnnualReport } from '../models/annual_report';
export type ApiAnnualReportState =
| 'available'
| 'generating'
| 'eligible'
| 'ineligible';
export const apiGetAnnualReportState = async (year: number) => {
const response = await api().get<{ state: ApiAnnualReportState }>(
`/api/v1/annual_reports/${year}/state`,
);
return {
state: response.data.state,
refresh: getAsyncRefreshHeader(response),
};
};
export const apiRequestGenerateAnnualReport = async (year: number) => {
const response = await api().post(`/api/v1/annual_reports/${year}/generate`);
return {
refresh: getAsyncRefreshHeader(response),
};
};
export interface ApiAnnualReportResponse {
annual_reports: AnnualReport[];
accounts: ApiAccountJSON[];
statuses: ApiStatusJSON[];
}
export const apiGetAnnualReport = (year: number) =>
apiRequestGet<ApiAnnualReportResponse>(`v1/annual_reports/${year}`);

View File

@@ -1,8 +1,9 @@
// See app/serializers/rest/account_serializer.rb
// See app/serializers/rest/custom_emoji_serializer.rb
export interface ApiCustomEmojiJSON {
shortcode: string;
static_url: string;
url: string;
category?: string;
featured?: boolean;
visible_in_picker: boolean;
}

View File

@@ -102,8 +102,7 @@ export interface ApiAccountWarningJSON {
appeal: unknown;
}
interface ModerationWarningNotificationGroupJSON
extends BaseNotificationGroupJSON {
interface ModerationWarningNotificationGroupJSON extends BaseNotificationGroupJSON {
type: 'moderation_warning';
moderation_warning: ApiAccountWarningJSON;
}
@@ -123,14 +122,12 @@ export interface ApiAccountRelationshipSeveranceEventJSON {
created_at: string;
}
interface AccountRelationshipSeveranceNotificationGroupJSON
extends BaseNotificationGroupJSON {
interface AccountRelationshipSeveranceNotificationGroupJSON extends BaseNotificationGroupJSON {
type: 'severed_relationships';
event: ApiAccountRelationshipSeveranceEventJSON;
}
interface AccountRelationshipSeveranceNotificationJSON
extends BaseNotificationJSON {
interface AccountRelationshipSeveranceNotificationJSON extends BaseNotificationJSON {
type: 'severed_relationships';
event: ApiAccountRelationshipSeveranceEventJSON;
}

View File

@@ -51,7 +51,7 @@ export interface ApiPreviewCardJSON {
html: string;
width: number;
height: number;
image: string;
image: string | null;
image_description: string;
embed_url: string;
blurhash: string;

View File

@@ -1,9 +1,5 @@
import Rails from '@rails/ujs';
import { setupLinkListeners } from './utils/links';
export function start() {
try {
Rails.start();
} catch {
// If called twice
}
setupLinkListeners();
}

View File

@@ -6,6 +6,7 @@ import CheckIcon from '@/material-icons/400-24px/check.svg?react';
import { Icon } from 'flavours/glitch/components/icon';
import type { Account } from 'flavours/glitch/models/account';
import { CustomEmojiProvider } from './emoji/context';
import { EmojiHTML } from './emoji/html';
import { useElementHandledLink } from './status/handled_link';
@@ -21,13 +22,12 @@ export const AccountFields: React.FC<Pick<Account, 'fields' | 'emojis'>> = ({
}
return (
<>
<CustomEmojiProvider emojis={emojis}>
{fields.map((pair, i) => (
<dl key={i} className={classNames({ verified: pair.verified_at })}>
<EmojiHTML
as='dt'
htmlString={pair.name_emojified}
extraEmojis={emojis}
className='translate'
{...htmlHandlers}
/>
@@ -52,13 +52,12 @@ export const AccountFields: React.FC<Pick<Account, 'fields' | 'emojis'>> = ({
<EmojiHTML
as='span'
htmlString={pair.value_emojified}
extraEmojis={emojis}
{...htmlHandlers}
/>
</dd>
</dl>
))}
</>
</CustomEmojiProvider>
);
};

View File

@@ -49,7 +49,11 @@ export const Alert: React.FC<{
</span>
{hasAction && (
<button className='notification-bar__action' onClick={onActionClick}>
<button
className='notification-bar__action'
onClick={onActionClick}
type='button'
>
{action}
</button>
)}

View File

@@ -47,7 +47,7 @@ export const AltTextBadge: React.FC<{ description: string }> = ({
rootClose
onHide={handleClose}
show={open}
target={anchorRef.current}
target={anchorRef}
placement='top-end'
flip
offset={offset}

View File

@@ -159,8 +159,8 @@ export default class AutosuggestInput extends ImmutablePureComponent {
this.input.focus();
};
UNSAFE_componentWillReceiveProps (nextProps) {
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
componentDidUpdate (prevProps) {
if (prevProps.suggestions !== this.props.suggestions && this.props.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
this.setState({ suggestionsHidden: false });
}
}

View File

@@ -50,6 +50,7 @@ const AutosuggestTextarea = forwardRef(({
onKeyUp,
onKeyDown,
onPaste,
onDrop,
onFocus,
autoFocus = true,
lang,
@@ -153,6 +154,12 @@ const AutosuggestTextarea = forwardRef(({
onPaste(e);
}, [onPaste]);
const handleDrop = useCallback((e) => {
if (onDrop) {
onDrop(e);
}
}, [onDrop]);
// Show the suggestions again whenever they change and the textarea is focused
useEffect(() => {
if (suggestions.size > 0 && textareaRef.current === document.activeElement) {
@@ -204,6 +211,7 @@ const AutosuggestTextarea = forwardRef(({
onFocus={handleFocus}
onBlur={handleBlur}
onPaste={handlePaste}
onDrop={handleDrop}
dir='auto'
aria-autocomplete='list'
aria-label={placeholder}
@@ -235,6 +243,7 @@ AutosuggestTextarea.propTypes = {
onKeyUp: PropTypes.func,
onKeyDown: PropTypes.func,
onPaste: PropTypes.func.isRequired,
onDrop: PropTypes.func,
onFocus:PropTypes.func,
autoFocus: PropTypes.bool,
lang: PropTypes.string,

View File

@@ -5,8 +5,10 @@ import classNames from 'classnames';
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
interface BaseProps
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
interface BaseProps extends Omit<
React.ButtonHTMLAttributes<HTMLButtonElement>,
'children'
> {
block?: boolean;
secondary?: boolean;
plain?: boolean;
@@ -78,6 +80,7 @@ export const Button: React.FC<Props> = ({
aria-live={loading !== undefined ? 'polite' : undefined}
onClick={handleClick}
title={title}
// eslint-disable-next-line react/button-has-type -- set correctly via TS
type={type}
{...props}
>

View File

@@ -0,0 +1,126 @@
import type { FC } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { fn, userEvent, expect } from 'storybook/test';
import type { CarouselProps } from './index';
import { Carousel } from './index';
interface TestSlideProps {
id: number;
text: string;
color: string;
}
const TestSlide: FC<TestSlideProps & { active: boolean }> = ({
active,
text,
color,
}) => (
<div
className='test-slide'
style={{
backgroundColor: active ? color : undefined,
}}
>
{text}
</div>
);
const slides: TestSlideProps[] = [
{
id: 1,
text: 'first',
color: 'red',
},
{
id: 2,
text: 'second',
color: 'pink',
},
{
id: 3,
text: 'third',
color: 'orange',
},
];
type StoryProps = Pick<
CarouselProps<TestSlideProps>,
'items' | 'renderItem' | 'emptyFallback' | 'onChangeSlide'
>;
const meta = {
title: 'Components/Carousel',
args: {
items: slides,
renderItem(item, active) {
return <TestSlide {...item} active={active} key={item.id} />;
},
onChangeSlide: fn(),
emptyFallback: 'No slides available',
},
render(args) {
return (
<>
<Carousel {...args} />
<style>
{`.test-slide {
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
font-weight: bold;
min-height: 100px;
transition: background-color 0.3s;
background-color: black;
}`}
</style>
</>
);
},
argTypes: {
emptyFallback: {
type: 'string',
},
},
tags: ['test'],
} satisfies Meta<StoryProps>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
async play({ args, canvas }) {
const nextButton = await canvas.findByRole('button', { name: /next/i });
const slides = await canvas.findAllByRole('group');
await expect(slides).toHaveLength(slides.length);
await userEvent.click(nextButton);
await expect(args.onChangeSlide).toHaveBeenCalledWith(1, slides[1]);
await userEvent.click(nextButton);
await expect(args.onChangeSlide).toHaveBeenCalledWith(2, slides[2]);
// Wrap around
await userEvent.click(nextButton);
await expect(args.onChangeSlide).toHaveBeenCalledWith(0, slides[0]);
},
};
export const DifferentHeights: Story = {
args: {
items: slides.map((props, index) => ({
...props,
styles: { height: 100 + index * 100 },
})),
},
};
export const NoSlides: Story = {
args: {
items: [],
},
};

View File

@@ -0,0 +1,244 @@
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
import type {
ComponentPropsWithoutRef,
ComponentType,
ReactElement,
ReactNode,
} from 'react';
import type { MessageDescriptor } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import classNames from 'classnames';
import { usePrevious } from '@dnd-kit/utilities';
import { animated, useSpring } from '@react-spring/web';
import { useDrag } from '@use-gesture/react';
import type { CarouselPaginationProps } from './pagination';
import { CarouselPagination } from './pagination';
import './styles.scss';
const defaultMessages = defineMessages({
previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
next: { id: 'lightbox.next', defaultMessage: 'Next' },
current: {
id: 'carousel.current',
defaultMessage: '<sr>Slide</sr> {current, number} / {max, number}',
},
slide: {
id: 'carousel.slide',
defaultMessage: 'Slide {current, number} of {max, number}',
},
});
export type MessageKeys = keyof typeof defaultMessages;
export interface CarouselSlideProps {
id: string | number;
}
export type RenderSlideFn<
SlideProps extends CarouselSlideProps = CarouselSlideProps,
> = (item: SlideProps, active: boolean, index: number) => ReactElement;
export interface CarouselProps<
SlideProps extends CarouselSlideProps = CarouselSlideProps,
> {
items: SlideProps[];
renderItem: RenderSlideFn<SlideProps>;
onChangeSlide?: (index: number, ref: Element) => void;
paginationComponent?: ComponentType<CarouselPaginationProps> | null;
paginationProps?: Partial<CarouselPaginationProps>;
messages?: Record<MessageKeys, MessageDescriptor>;
emptyFallback?: ReactNode;
classNamePrefix?: string;
slideClassName?: string;
}
export const Carousel = <
SlideProps extends CarouselSlideProps = CarouselSlideProps,
>({
items,
renderItem,
onChangeSlide,
paginationComponent: Pagination = CarouselPagination,
paginationProps = {},
messages = defaultMessages,
children,
emptyFallback = null,
className,
classNamePrefix = 'carousel',
slideClassName,
...wrapperProps
}: CarouselProps<SlideProps> & ComponentPropsWithoutRef<'div'>) => {
// Handle slide change
const [slideIndex, setSlideIndex] = useState(0);
const wrapperRef = useRef<HTMLDivElement>(null);
// Handle slide heights
const [currentSlideHeight, setCurrentSlideHeight] = useState(
() => wrapperRef.current?.scrollHeight ?? 0,
);
const previousSlideHeight = usePrevious(currentSlideHeight);
const handleSlideChange = useCallback(
(direction: number) => {
setSlideIndex((prev) => {
const max = items.length - 1;
let newIndex = prev + direction;
if (newIndex < 0) {
newIndex = max;
} else if (newIndex > max) {
newIndex = 0;
}
const slide = wrapperRef.current?.children[newIndex];
if (slide) {
setCurrentSlideHeight(slide.scrollHeight);
if (slide instanceof HTMLElement) {
onChangeSlide?.(newIndex, slide);
}
}
return newIndex;
});
},
[items.length, onChangeSlide],
);
const observerRef = useRef<ResizeObserver | null>(null);
observerRef.current ??= new ResizeObserver(() => {
handleSlideChange(0);
});
const wrapperStyles = useSpring({
x: `-${slideIndex * 100}%`,
height: currentSlideHeight,
// Don't animate from zero to the height of the initial slide
immediate: !previousSlideHeight,
});
useLayoutEffect(() => {
// Update slide height when the component mounts
if (currentSlideHeight === 0) {
handleSlideChange(0);
}
}, [currentSlideHeight, handleSlideChange]);
// Handle swiping animations
const bind = useDrag(
({ swipe: [swipeX] }) => {
handleSlideChange(swipeX * -1); // Invert swipe as swiping left loads the next slide.
},
{ pointer: { capture: false } },
);
const handlePrev = useCallback(() => {
handleSlideChange(-1);
// We're focusing on the wrapper as the child slides can potentially be inert.
// Because of that, only the active slide can be focused anyway.
wrapperRef.current?.focus();
}, [handleSlideChange]);
const handleNext = useCallback(() => {
handleSlideChange(1);
wrapperRef.current?.focus();
}, [handleSlideChange]);
const intl = useIntl();
if (items.length === 0) {
return emptyFallback;
}
return (
<div
{...bind()}
aria-roledescription='carousel'
role='region'
className={classNames(classNamePrefix, className)}
{...wrapperProps}
>
<div className={`${classNamePrefix}__header`}>
{children}
{Pagination && items.length > 1 && (
<Pagination
current={slideIndex}
max={items.length}
onNext={handleNext}
onPrev={handlePrev}
className={`${classNamePrefix}__pagination`}
messages={messages}
{...paginationProps}
/>
)}
</div>
<animated.div
className={`${classNamePrefix}__slides`}
ref={wrapperRef}
style={wrapperStyles}
aria-label={intl.formatMessage(messages.slide, {
current: slideIndex + 1,
max: items.length,
})}
tabIndex={-1}
>
{items.map((itemsProps, index) => (
<CarouselSlideWrapper<SlideProps>
item={itemsProps}
renderItem={renderItem}
observer={observerRef.current}
index={index}
key={`slide-${itemsProps.id}`}
className={classNames(`${classNamePrefix}__slide`, slideClassName, {
active: index === slideIndex,
})}
active={index === slideIndex}
/>
))}
</animated.div>
</div>
);
};
type CarouselSlideWrapperProps<SlideProps extends CarouselSlideProps> = {
observer: ResizeObserver | null;
className: string;
active: boolean;
item: SlideProps;
index: number;
} & Pick<CarouselProps<SlideProps>, 'renderItem'>;
const CarouselSlideWrapper = <SlideProps extends CarouselSlideProps>({
observer,
className,
active,
renderItem,
item,
index,
}: CarouselSlideWrapperProps<SlideProps>) => {
const handleRef = useCallback(
(instance: HTMLDivElement | null) => {
if (observer && instance) {
observer.observe(instance);
}
},
[observer],
);
const children = useMemo(
() => renderItem(item, active, index),
[renderItem, item, active, index],
);
return (
<div
ref={handleRef}
className={className}
role='group'
aria-roledescription='slide'
inert={active ? undefined : ''}
data-index={index}
>
{children}
</div>
);
};

View File

@@ -0,0 +1,54 @@
import type { FC, MouseEventHandler } from 'react';
import type { MessageDescriptor } from 'react-intl';
import { useIntl } from 'react-intl';
import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { IconButton } from '../icon_button';
import type { MessageKeys } from './index';
export interface CarouselPaginationProps {
onNext: MouseEventHandler;
onPrev: MouseEventHandler;
current: number;
max: number;
className?: string;
messages: Record<MessageKeys, MessageDescriptor>;
}
export const CarouselPagination: FC<CarouselPaginationProps> = ({
onNext,
onPrev,
current,
max,
className = '',
messages,
}) => {
const intl = useIntl();
return (
<div className={className}>
<IconButton
title={intl.formatMessage(messages.previous)}
icon='chevron-left'
iconComponent={ChevronLeftIcon}
onClick={onPrev}
/>
<span aria-live='polite'>
{intl.formatMessage(messages.current, {
current: current + 1,
max,
sr: (chunk) => <span className='sr-only'>{chunk}</span>,
})}
</span>
<IconButton
title={intl.formatMessage(messages.next)}
icon='chevron-right'
iconComponent={ChevronRightIcon}
onClick={onNext}
/>
</div>
);
};

View File

@@ -0,0 +1,28 @@
.carousel {
gap: 16px;
overflow: hidden;
touch-action: pan-y;
&__header {
padding: 8px 16px;
}
&__pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
&__slides {
display: flex;
flex-wrap: nowrap;
align-items: start;
}
&__slide {
flex: 0 0 100%;
width: 100%;
overflow: hidden;
}
}

View File

@@ -30,7 +30,7 @@ export const ColumnBackButton: React.FC<{ onClick?: OnClickCallback }> = ({
const handleClick = useHandleClick(onClick);
const component = (
<button onClick={handleClick} className='column-back-button'>
<button onClick={handleClick} className='column-back-button' type='button'>
<Icon
id='chevron-left'
icon={ArrowBackIcon}

View File

@@ -53,6 +53,7 @@ const BackButton: React.FC<{
compact: onlyIcon,
})}
aria-label={intl.formatMessage(messages.back)}
type='button'
>
<Icon
id='chevron-left'
@@ -172,6 +173,7 @@ export const ColumnHeader: React.FC<Props> = ({
<button
className='text-btn column-header__setting-btn'
onClick={handlePin}
type='button'
>
<Icon id='times' icon={CloseIcon} />{' '}
<FormattedMessage id='column_header.unpin' defaultMessage='Unpin' />
@@ -185,6 +187,7 @@ export const ColumnHeader: React.FC<Props> = ({
aria-label={intl.formatMessage(messages.moveLeft)}
className='icon-button column-header__setting-btn'
onClick={handleMoveLeft}
type='button'
>
<Icon id='chevron-left' icon={ChevronLeftIcon} />
</button>
@@ -193,6 +196,7 @@ export const ColumnHeader: React.FC<Props> = ({
aria-label={intl.formatMessage(messages.moveRight)}
className='icon-button column-header__setting-btn'
onClick={handleMoveRight}
type='button'
>
<Icon id='chevron-right' icon={ChevronRightIcon} />
</button>
@@ -203,6 +207,7 @@ export const ColumnHeader: React.FC<Props> = ({
<button
className='text-btn column-header__setting-btn'
onClick={handlePin}
type='button'
>
<Icon id='plus' icon={AddIcon} />{' '}
<FormattedMessage id='column_header.pin' defaultMessage='Pin' />
@@ -237,6 +242,7 @@ export const ColumnHeader: React.FC<Props> = ({
collapsed ? messages.show : messages.hide,
)}
onClick={handleToggleClick}
type='button'
>
<i className='icon-with-badge'>
<Icon
@@ -259,7 +265,11 @@ export const ColumnHeader: React.FC<Props> = ({
<>
{backButton}
<button onClick={handleTitleClick} className='column-header__title'>
<button
onClick={handleTitleClick}
className='column-header__title'
type='button'
>
{!backButton && (
<Icon
id={icon}

View File

@@ -1,4 +1,4 @@
import { useCallback, useState, useEffect, useRef } from 'react';
import { useCallback, useState, useRef } from 'react';
import { FormattedMessage } from 'react-intl';
@@ -12,11 +12,15 @@ export const ColumnSearchHeader: React.FC<{
const inputRef = useRef<HTMLInputElement>(null);
const [value, setValue] = useState('');
useEffect(() => {
// Reset the component when it turns from active to inactive.
// [More on this pattern](https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)
const [previousActive, setPreviousActive] = useState(active);
if (active !== previousActive) {
setPreviousActive(active);
if (!active) {
setValue('');
}
}, [active]);
}
const handleChange = useCallback(
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => {

View File

@@ -74,7 +74,7 @@ export const CopyPasteText: React.FC<{ value: string }> = ({ value }) => {
onBlur={handleBlur}
/>
<button className='button' onClick={handleButtonClick}>
<button className='button' onClick={handleButtonClick} type='button'>
<Icon id='copy' icon={ContentCopyIcon} />{' '}
{copied ? (
<FormattedMessage id='copypaste.copied' defaultMessage='Copied' />

View File

@@ -1,12 +1,10 @@
import type { PropsWithChildren } from 'react';
import { useCallback, useState, useEffect } from 'react';
import type { FC, ReactNode } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import { changeSetting } from 'flavours/glitch/actions/settings';
import { bannerSettings } from 'flavours/glitch/settings';
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
import { useDismissible } from '../hooks/useDismissible';
import { IconButton } from './icon_button';
@@ -16,48 +14,12 @@ const messages = defineMessages({
interface Props {
id: string;
children: ReactNode;
}
export function useDismissableBannerState({ id }: Props) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const dismissed: boolean = useAppSelector((state) =>
/* eslint-disable-next-line */
state.settings.getIn(['dismissed_banners', id], false),
);
const [isVisible, setIsVisible] = useState(
!bannerSettings.get(id) && !dismissed,
);
const dispatch = useAppDispatch();
const dismiss = useCallback(() => {
setIsVisible(false);
bannerSettings.set(id, true);
dispatch(changeSetting(['dismissed_banners', id], true));
}, [id, dispatch]);
useEffect(() => {
// Store legacy localStorage setting on server
if (!isVisible && !dismissed) {
dispatch(changeSetting(['dismissed_banners', id], true));
}
}, [id, dispatch, isVisible, dismissed]);
return {
wasDismissed: !isVisible,
dismiss,
};
}
export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
id,
children,
}) => {
export const DismissableBanner: FC<Props> = ({ id, children }) => {
const intl = useIntl();
const { wasDismissed, dismiss } = useDismissableBannerState({
id,
});
const { wasDismissed, dismiss } = useDismissible(id);
if (wasDismissed) {
return null;

View File

@@ -109,7 +109,7 @@ export const Dropdown: FC<
placement='bottom-start'
onHide={handleClose}
flip
target={buttonRef.current}
target={buttonRef}
popperConfig={{
strategy: 'fixed',
modifiers: [matchWidth],

View File

@@ -216,6 +216,7 @@ export const DropdownMenu = <Item = MenuItem,>({
onClick={handleItemClick}
data-index={i}
aria-disabled={disabled}
type='button'
>
<DropdownMenuItemContent item={option} />
</button>
@@ -308,7 +309,7 @@ interface DropdownProps<Item extends object | null = MenuItem> {
renderItem?: RenderItemFn<Item>;
renderHeader?: RenderHeaderFn<Item>;
onOpen?: // Must use a union type for the full function as a union with void is not allowed.
| ((event: React.MouseEvent | React.KeyboardEvent) => void)
| ((event: React.MouseEvent | React.KeyboardEvent) => void)
| ((event: React.MouseEvent | React.KeyboardEvent) => boolean);
onItemClick?: ItemClickFn<Item>;
}

View File

@@ -108,7 +108,7 @@ export const EditedTimestamp: React.FC<{
onItemClick={handleItemClick}
forceDropdown
>
<button className='dropdown-menu__text-button'>
<button className='dropdown-menu__text-button' type='button'>
<FormattedMessage
id='status.edited'
defaultMessage='Edited {date}'

View File

@@ -2,24 +2,27 @@ import type { ComponentProps } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { importCustomEmojiData } from '@/flavours/glitch/features/emoji/loader';
import { customEmojiFactory } from '@/testing/factories';
import { CustomEmojiProvider } from './context';
import { Emoji } from './index';
type EmojiProps = ComponentProps<typeof Emoji> & { state: string };
type EmojiProps = ComponentProps<typeof Emoji> & {
style: 'auto' | 'native' | 'twemoji';
};
const meta = {
title: 'Components/Emoji',
component: Emoji,
args: {
code: '🖤',
state: 'auto',
style: 'auto',
},
argTypes: {
code: {
name: 'Emoji',
},
state: {
style: {
control: {
type: 'select',
labels: {
@@ -30,16 +33,15 @@ const meta = {
},
options: ['auto', 'native', 'twemoji'],
name: 'Emoji Style',
mapping: {
auto: { meta: { emoji_style: 'auto' } },
native: { meta: { emoji_style: 'native' } },
twemoji: { meta: { emoji_style: 'twemoji' } },
},
reduxPath: 'meta.emoji_style',
},
},
render(args) {
void importCustomEmojiData();
return <Emoji {...args} />;
return (
<CustomEmojiProvider emojis={[customEmojiFactory()]}>
<Emoji {...args} />
</CustomEmojiProvider>
);
},
} satisfies Meta<EmojiProps>;

View File

@@ -1,9 +1,17 @@
import type { FC } from 'react';
import { useContext, useEffect, useState } from 'react';
import { EMOJI_TYPE_CUSTOM } from '@/flavours/glitch/features/emoji/constants';
import classNames from 'classnames';
import {
EMOJI_TYPE_CUSTOM,
EMOJI_TYPE_UNICODE,
} from '@/flavours/glitch/features/emoji/constants';
import { useEmojiAppState } from '@/flavours/glitch/features/emoji/mode';
import { unicodeHexToUrl } from '@/flavours/glitch/features/emoji/normalize';
import {
emojiToInversionClassName,
unicodeHexToUrl,
} from '@/flavours/glitch/features/emoji/normalize';
import {
isStateLoaded,
loadEmojiDataToState,
@@ -41,6 +49,7 @@ export const Emoji: FC<EmojiProps> = ({
}, [appState.currentLocale, state]);
const animate = useContext(AnimateEmojiContext);
const fallback = showFallback ? code : null;
// If the code is invalid or we otherwise know it's not valid, show the fallback.
@@ -48,10 +57,6 @@ export const Emoji: FC<EmojiProps> = ({
return fallback;
}
if (!shouldRenderImage(state, appState.mode)) {
return code;
}
if (!isStateLoaded(state)) {
if (showLoading) {
return <span className='emojione emoji-loading' title={code} />;
@@ -59,6 +64,17 @@ export const Emoji: FC<EmojiProps> = ({
return fallback;
}
const inversionClass =
state.type === EMOJI_TYPE_UNICODE &&
emojiToInversionClassName(state.data.unicode);
if (!shouldRenderImage(state, appState.mode)) {
if (state.type === EMOJI_TYPE_UNICODE) {
return state.data.unicode;
}
return code;
}
if (state.type === EMOJI_TYPE_CUSTOM) {
const shortcode = `:${state.code}:`;
return (
@@ -79,7 +95,7 @@ export const Emoji: FC<EmojiProps> = ({
src={src}
alt={state.data.unicode}
title={state.data.label}
className='emojione'
className={classNames('emojione', inversionClass)}
loading='lazy'
/>
);

View File

@@ -27,22 +27,23 @@ export const ExitAnimationWrapper: React.FC<{
*/
children: (delayedIsActive: boolean) => React.ReactNode;
}> = ({ isActive = false, delayMs = 500, withEntryDelay, children }) => {
const [delayedIsActive, setDelayedIsActive] = useState(false);
const [delayedIsActive, setDelayedIsActive] = useState(
isActive && !withEntryDelay,
);
useEffect(() => {
if (isActive && !withEntryDelay) {
setDelayedIsActive(true);
const withDelay = !isActive || withEntryDelay;
return () => '';
} else {
const timeout = setTimeout(() => {
const timeout = setTimeout(
() => {
setDelayedIsActive(isActive);
}, delayMs);
},
withDelay ? delayMs : 0,
);
return () => {
clearTimeout(timeout);
};
}
return () => {
clearTimeout(timeout);
};
}, [isActive, delayMs, withEntryDelay]);
if (!isActive && !delayedIsActive) {

View File

@@ -1,38 +1,43 @@
import type { ComponentPropsWithRef } from 'react';
import {
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
useId,
} from 'react';
import { useCallback, useEffect, useId } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { defineMessages, FormattedMessage } from 'react-intl';
import type { Map as ImmutableMap } from 'immutable';
import { List as ImmutableList } from 'immutable';
import type { AnimatedProps } from '@react-spring/web';
import { animated, useSpring } from '@react-spring/web';
import { useDrag } from '@use-gesture/react';
import { expandAccountFeaturedTimeline } from '@/flavours/glitch/actions/timelines';
import { Icon } from '@/flavours/glitch/components/icon';
import { IconButton } from '@/flavours/glitch/components/icon_button';
import { StatusQuoteManager } from '@/flavours/glitch/components/status_quoted';
import { usePrevious } from '@/flavours/glitch/hooks/usePrevious';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import {
createAppSelector,
useAppDispatch,
useAppSelector,
} from '@/flavours/glitch/store';
import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react';
import { Carousel } from './carousel';
const pinnedStatusesSelector = createAppSelector(
[
(state, accountId: string, tagged?: string) =>
(state.timelines as ImmutableMap<string, unknown>).getIn(
[`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'],
ImmutableList(),
) as ImmutableList<string>,
],
(items) => items.toArray().map((id) => ({ id })),
);
const messages = defineMessages({
previous: { id: 'featured_carousel.previous', defaultMessage: 'Previous' },
next: { id: 'featured_carousel.next', defaultMessage: 'Next' },
previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
next: { id: 'lightbox.next', defaultMessage: 'Next' },
current: {
id: 'featured_carousel.current',
defaultMessage: '<sr>Post</sr> {current, number} / {max, number}',
},
slide: {
id: 'featured_carousel.slide',
defaultMessage: '{index} of {total}',
defaultMessage: 'Post {current, number} of {max, number}',
},
});
@@ -40,7 +45,6 @@ export const FeaturedCarousel: React.FC<{
accountId: string;
tagged?: string;
}> = ({ accountId, tagged }) => {
const intl = useIntl();
const accessibilityId = useId();
// Load pinned statuses
@@ -50,175 +54,37 @@ export const FeaturedCarousel: React.FC<{
void dispatch(expandAccountFeaturedTimeline(accountId, { tagged }));
}
}, [accountId, dispatch, tagged]);
const pinnedStatuses = useAppSelector(
(state) =>
(state.timelines as ImmutableMap<string, unknown>).getIn(
[`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'],
ImmutableList(),
) as ImmutableList<string>,
const pinnedStatuses = useAppSelector((state) =>
pinnedStatusesSelector(state, accountId, tagged),
);
// Handle slide change
const [slideIndex, setSlideIndex] = useState(0);
const wrapperRef = useRef<HTMLDivElement>(null);
const handleSlideChange = useCallback(
(direction: number) => {
setSlideIndex((prev) => {
const max = pinnedStatuses.size - 1;
let newIndex = prev + direction;
if (newIndex < 0) {
newIndex = max;
} else if (newIndex > max) {
newIndex = 0;
}
const slide = wrapperRef.current?.children[newIndex];
if (slide) {
setCurrentSlideHeight(slide.scrollHeight);
}
return newIndex;
});
},
[pinnedStatuses.size],
const renderSlide = useCallback(
({ id }: { id: string }) => (
<StatusQuoteManager id={id} contextType='account' withCounters />
),
[],
);
// Handle slide heights
const [currentSlideHeight, setCurrentSlideHeight] = useState(
wrapperRef.current?.scrollHeight ?? 0,
);
const previousSlideHeight = usePrevious(currentSlideHeight);
const observerRef = useRef<ResizeObserver>(
new ResizeObserver(() => {
handleSlideChange(0);
}),
);
const wrapperStyles = useSpring({
x: `-${slideIndex * 100}%`,
height: currentSlideHeight,
// Don't animate from zero to the height of the initial slide
immediate: !previousSlideHeight,
});
useLayoutEffect(() => {
// Update slide height when the component mounts
if (currentSlideHeight === 0) {
handleSlideChange(0);
}
}, [currentSlideHeight, handleSlideChange]);
// Handle swiping animations
const bind = useDrag(({ swipe: [swipeX] }) => {
handleSlideChange(swipeX * -1); // Invert swipe as swiping left loads the next slide.
});
const handlePrev = useCallback(() => {
handleSlideChange(-1);
}, [handleSlideChange]);
const handleNext = useCallback(() => {
handleSlideChange(1);
}, [handleSlideChange]);
if (!accountId || pinnedStatuses.isEmpty()) {
if (!accountId || pinnedStatuses.length === 0) {
return null;
}
return (
<div
className='featured-carousel'
{...bind()}
aria-roledescription='carousel'
<Carousel
items={pinnedStatuses}
renderItem={renderSlide}
aria-labelledby={`${accessibilityId}-title`}
role='region'
classNamePrefix='featured-carousel'
messages={messages}
>
<div className='featured-carousel__header'>
<h4
className='featured-carousel__title'
id={`${accessibilityId}-title`}
>
<Icon id='thumb-tack' icon={PushPinIcon} />
<FormattedMessage
id='featured_carousel.header'
defaultMessage='{count, plural, one {Pinned Post} other {Pinned Posts}}'
values={{ count: pinnedStatuses.size }}
/>
</h4>
{pinnedStatuses.size > 1 && (
<>
<IconButton
title={intl.formatMessage(messages.previous)}
icon='chevron-left'
iconComponent={ChevronLeftIcon}
onClick={handlePrev}
/>
<span aria-live='polite'>
<FormattedMessage
id='featured_carousel.post'
defaultMessage='Post'
>
{(text) => <span className='sr-only'>{text}</span>}
</FormattedMessage>
{slideIndex + 1} / {pinnedStatuses.size}
</span>
<IconButton
title={intl.formatMessage(messages.next)}
icon='chevron-right'
iconComponent={ChevronRightIcon}
onClick={handleNext}
/>
</>
)}
</div>
<animated.div
className='featured-carousel__slides'
ref={wrapperRef}
style={wrapperStyles}
aria-atomic='false'
aria-live='polite'
>
{pinnedStatuses.map((statusId, index) => (
<FeaturedCarouselItem
key={`f-${statusId}`}
data-index={index}
aria-label={intl.formatMessage(messages.slide, {
index: index + 1,
total: pinnedStatuses.size,
})}
statusId={statusId}
observer={observerRef.current}
active={index === slideIndex}
/>
))}
</animated.div>
</div>
);
};
interface FeaturedCarouselItemProps {
statusId: string;
active: boolean;
observer: ResizeObserver;
}
const FeaturedCarouselItem: React.FC<
FeaturedCarouselItemProps & AnimatedProps<ComponentPropsWithRef<'div'>>
> = ({ statusId, active, observer, ...props }) => {
const handleRef = useCallback(
(instance: HTMLDivElement | null) => {
if (instance) {
observer.observe(instance);
}
},
[observer],
);
return (
<animated.div
className='featured-carousel__slide'
// @ts-expect-error inert in not in this version of React
inert={!active ? 'true' : undefined}
aria-roledescription='slide'
role='group'
ref={handleRef}
{...props}
>
<StatusQuoteManager id={statusId} contextType='account' withCounters />
</animated.div>
<h4 className='featured-carousel__title' id={`${accessibilityId}-title`}>
<Icon id='thumb-tack' icon={PushPinIcon} />
<FormattedMessage
id='featured_carousel.header'
defaultMessage='{count, plural, one {Pinned Post} other {Pinned Posts}}'
values={{ count: pinnedStatuses.length }}
/>
</h4>
</Carousel>
);
};

View File

@@ -235,7 +235,7 @@ const HashtagBar: React.FC<{
))}
{!expanded && hashtags.length > VISIBLE_HASHTAGS && (
<button className='link-button' onClick={handleClick}>
<button className='link-button' onClick={handleClick} type='button'>
<FormattedMessage
id='hashtags.and_other'
defaultMessage='…and {count, plural, other {# more}}'

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