Compare commits

..

475 Commits

Author SHA1 Message Date
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
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
932 changed files with 20407 additions and 17866 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.11

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

@@ -31,7 +31,7 @@ const config: StorybookConfig = {
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

@@ -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,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,9 +2,50 @@
All notable changes to this project will be documented in this file.
## [4.5.3] - 2025-12-08
### Security
- Fix inconsistent error handling leaking information on existence of private posts ([GHSA-gwhw-gcjx-72v8](https://github.com/mastodon/mastodon/security/advisories/GHSA-gwhw-gcjx-72v8))
### Fixed
- Fix “Delete and Redraft” on a non-quote being treated as a quote post in some cases (#37140 by @ClearlyClaire)
- Fix YouTube embeds by sending referer (#37126 by @ChaosExAnima)
- Fix streamed quoted polls not being hydrated correctly (#37118 by @ClearlyClaire)
- Fix creation of duplicate conversations (#37108 by @oneiros)
- Fix extraneous `noreferrer` in external links (#37107 by @ChaosExAnima)
- Fix edge case error handling in some database migrations (#37079 by @ClearlyClaire)
- Fix error handling when re-fetching already-known statuses (#37077 by @ClearlyClaire)
- Fix post navigation in single-column mode when Advanced UI is enabled (#37044 by @diondiondion)
- Fix `tootctl status remove` removing quoted posts and remote quotes of local posts (#37009 by @ClearlyClaire)
- Fix known expensive S3 batch delete operation failing because of short timeouts (#37004 by @ClearlyClaire)
- Fix compose autosuggest always lowercasing input token (#36995 by @ClearlyClaire)
## [4.5.2] - 2025-11-20
### Changed
- Change private quote education modal to not show up on self-quotes (#36926 by @ClearlyClaire)
### Fixed
- Fix missing fallback link in CW-only quote posts (#36963 by @ClearlyClaire)
- Fix statuses without text being hidden while loading (#36962 by @ClearlyClaire)
- Fix `g` + `h` keyboard shortcut not working when a post is focused (#36935 by @diondiondion)
- Fix quoting overwriting current content warning (#36934 by @ClearlyClaire)
- Fix scroll-to-status in threaded view being unreliable (#36927 by @ClearlyClaire)
- Fix path resolution for emoji worker (#36897 by @ChaosExAnima)
- Fix `tootctl upgrade storage-schema` failing with `ArgumentError` (#36914 by @shugo)
- Fix cross-origin handling of CSS modules (#36890 by @ClearlyClaire)
- Fix error with remote tags including percent signs (#36886 and #36925 by @ChaosExAnima and @ClearlyClaire)
- Fix bogus quote approval policy not always being replaced correctly (#36885 by @ClearlyClaire)
- Fix hashtag completion not being inserted correctly (#36884 by @ClearlyClaire)
- Fix Cmd/Ctrl + Enter in the composer triggering confirmation dialog action (#36870 by @diondiondion)
## [4.5.1] - 2025-11-13
### Fixes
### Fixed
- Fix Cmd/Ctrl + Enter not submitting Alt text modal on some browsers (#36866 by @diondiondion)
- Fix posts coming from public/hashtag streaming being marked as unquotable (#36860 and #36869 by @ClearlyClaire)

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.56.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

@@ -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.1190.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.206.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
@@ -164,7 +167,7 @@ GEM
cocoon (1.2.15)
color_diff (0.1)
concurrent-ruby (1.3.5)
connection_pool (2.5.4)
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.0)
debug (1.11.0)
irb (~> 1.10)
reline (>= 0.3.8)
@@ -231,7 +234,7 @@ GEM
excon (1.3.0)
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)
@@ -279,7 +282,7 @@ GEM
rake (>= 13)
googleapis-common-protos-types (1.22.0)
google-protobuf (~> 4.26)
haml (6.3.0)
haml (6.4.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.67.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)
@@ -346,7 +350,7 @@ GEM
azure-blob (~> 0.5.2)
hashie (~> 5.0)
jmespath (1.6.2)
json (2.15.1)
json (2.16.0)
json-canonicalization (1.0.0)
json-jwt (1.17.0)
activesupport (>= 4.2)
@@ -443,7 +447,7 @@ GEM
mime-types-data (3.2025.0924)
mini_mime (1.1.5)
mini_portile2 (2.8.9)
minitest (5.26.0)
minitest (5.26.2)
msgpack (1.8.0)
multi_json (1.17.0)
mutex_m (0.3.0)
@@ -465,7 +469,7 @@ GEM
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.0)
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.56.0)
concurrent-ruby (>= 1.1.6)
mime-types (>= 3.0)
pp (0.6.3)
@@ -604,8 +608,8 @@ 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)
@@ -614,7 +618,7 @@ GEM
psych (5.2.6)
date
stringio
public_suffix (6.0.2)
public_suffix (7.0.0)
puma (7.1.0)
nio4r (~> 2.0)
pundit (2.5.2)
@@ -634,7 +638,7 @@ GEM
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)
@@ -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)
@@ -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,10 +717,10 @@ 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)
rqrcode_core (2.0.1)
rspec (3.13.1)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
@@ -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)
@@ -775,10 +779,10 @@ GEM
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)
@@ -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)
@@ -835,9 +839,9 @@ GEM
stackprof (0.2.27)
starry (0.2.0)
base64
stoplight (5.4.0)
stoplight (5.6.0)
zeitwerk
stringio (3.1.7)
stringio (3.1.8)
strong_migrations (2.5.1)
activerecord (>= 7.1)
swd (2.0.3)
@@ -851,7 +855,7 @@ 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)
@@ -883,7 +887,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,7 +915,7 @@ 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)
@@ -933,12 +937,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 +1009,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 +1022,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 +1032,11 @@ DEPENDENCIES
parslet
pg (~> 1.5)
pghero
playwright-ruby-client (= 1.55.0)
playwright-ruby-client (= 1.56.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)

View File

@@ -22,7 +22,7 @@ class ActivityPub::LikesController < ActivityPub::BaseController
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -24,7 +24,7 @@ class ActivityPub::QuoteAuthorizationsController < ActivityPub::BaseController
return not_found unless @quote.status.present? && @quote.quoted_status.present?
authorize @quote.quoted_status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -25,7 +25,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -22,7 +22,7 @@ class ActivityPub::SharesController < ActivityPub::BaseController
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

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,14 +30,59 @@ 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
end
def refresh_key
"wrapstodon:#{current_account.id}:#{year}"
end
private
def report_state
return 'available' 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)
'generating'
elsif AnnualReport.current_campaign == year && AnnualReport.new(current_account, year).eligible?
'eligible'
else
'ineligible'
end
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

@@ -17,7 +17,7 @@ class Api::V1::Polls::VotesController < Api::BaseController
def set_poll
@poll = Poll.find(params[:poll_id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -17,7 +17,7 @@ class Api::V1::PollsController < Api::BaseController
def set_poll
@poll = Poll.find(params[:id])
authorize @poll.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -10,7 +10,7 @@ class Api::V1::Statuses::BaseController < Api::BaseController
def set_status
@status = Status.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -23,7 +23,7 @@ class Api::V1::Statuses::BookmarksController < Api::V1::Statuses::BaseController
bookmark&.destroy!
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -25,7 +25,7 @@ class Api::V1::Statuses::FavouritesController < Api::V1::Statuses::BaseControlle
relationships = StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false }, attributes_map: { @status.id => { favourites_count: count } })
render json: @status, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

View File

@@ -36,7 +36,7 @@ class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
relationships = StatusRelationshipsPresenter.new([@status], current_account.id, reblogs_map: { @reblog.id => false }, attributes_map: { @reblog.id => { reblogs_count: count } })
render json: @reblog, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
@@ -45,7 +45,7 @@ class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
def set_reblog
@reblog = Status.find(params[:status_id])
authorize @reblog, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -128,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) })
@@ -147,7 +148,7 @@ class Api::V1::StatusesController < Api::BaseController
def set_status
@status = Status.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
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

@@ -30,7 +30,7 @@ class Api::Web::EmbedsController < Api::Web::BaseController
def set_status
@status = Status.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end
end

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

@@ -21,7 +21,7 @@ class AuthorizeInteractionsController < ApplicationController
def set_resource
@resource = located_resource
authorize(@resource, :show?) if @resource.is_a?(Status)
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

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

@@ -34,7 +34,7 @@ class MediaController < ApplicationController
def verify_permitted_status!
authorize @media_attachment.status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
end

View File

@@ -62,7 +62,7 @@ class StatusesController < ApplicationController
def set_status
@status = @account.statuses.find(params[:id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found
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.seconds, 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

@@ -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,16 @@
# frozen_string_literal: true
module WrapstodonHelper
def render_wrapstodon_share_data(report)
json = ActiveModelSerializers::SerializableResource.new(
AnnualReportsPresenter.new([report]),
serializer: REST::AnnualReportsSerializer,
scope: nil,
scope_name: :current_user
).to_json
# rubocop:disable Rails/OutputSafety
content_tag(:script, json_escape(json).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');
@@ -305,7 +293,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 +306,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 +330,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,63 @@
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;
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 },
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

@@ -709,8 +709,8 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
dispatch(useEmoji(suggestion));
} else if (suggestion.type === 'hashtag') {
completion = suggestion.name.slice(token.length - 1);
startPosition = position + token.length;
completion = token + suggestion.name.slice(token.length - 1);
startPosition = position - 1;
} else if (suggestion.type === 'account') {
completion = `@${getState().getIn(['accounts', suggestion.id, 'acct'])}`;
startPosition = position - 1;

View File

@@ -104,7 +104,7 @@ export function normalizeStatus(status, normalOldStatus, { settings, bogusQuoteP
}
if (normalOldStatus) {
normalStatus.quote_approval ||= normalOldStatus.quote_approval;
normalStatus.quote_approval ||= normalOldStatus.get('quote_approval');
const list = normalOldStatus.get('media_attachments');
if (normalStatus.media_attachments && list) {

View File

@@ -1,3 +1,5 @@
import { checkAnnualReport } from '@/flavours/glitch/reducers/slices/annual_report';
import api from '../api';
import { importFetchedAccount } from './importer';
@@ -29,6 +31,9 @@ export const fetchServer = () => (dispatch, getState) => {
.get('/api/v2/instance').then(({ data }) => {
if (data.contact.account) dispatch(importFetchedAccount(data.contact.account));
dispatch(fetchServerSuccess(data));
if (data.wrapstodon) {
void dispatch(checkAnnualReport());
}
}).catch(err => dispatch(fetchServerFail(err)));
};

View File

@@ -85,6 +85,8 @@ export function fetchStatus(id, {
dispatch(fetchStatusSuccess(skipLoading));
}).catch(error => {
dispatch(fetchStatusFail(id, error, skipLoading, parentQuotePostId));
if (error.status === 404)
dispatch(deleteFromTimelines(id));
});
};
}

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

@@ -1,5 +1,6 @@
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { reinsertAnnualReport, TIMELINE_WRAPSTODON } from '@/flavours/glitch/reducers/slices/annual_report';
import api, { getLinks } from 'flavours/glitch/api';
import { compareId } from 'flavours/glitch/compare_id';
import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
@@ -7,7 +8,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 +26,16 @@ 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,
TIMELINE_WRAPSTODON,
];
export const loadPending = timeline => ({
type: TIMELINE_LOAD_PENDING,
timeline,
@@ -135,6 +143,7 @@ export function expandTimeline(timelineId, path, params = {}) {
if (timelineId === 'home') {
dispatch(submitMarkers());
dispatch(reinsertAnnualReport())
}
} catch(error) {
dispatch(expandTimelineFail(timelineId, error, isLoadingMore));

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

@@ -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

@@ -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

@@ -28,7 +28,7 @@ const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
return [null, null];
}
word = word.trim().toLowerCase();
word = word.trim();
if (word.length > 0) {
return [left + 1, word];
@@ -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

@@ -29,7 +29,7 @@ const textAtCursorMatchesToken = (str, caretPosition) => {
return [null, null];
}
word = word.trim().toLowerCase();
word = word.trim();
if (word.length > 0) {
return [left + 1, word];
@@ -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

@@ -78,6 +78,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

@@ -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>

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

@@ -1,9 +1,14 @@
import type { FC } from 'react';
import { useContext, useEffect, useState } from 'react';
import classNames from 'classnames';
import { EMOJI_TYPE_CUSTOM } 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 +46,9 @@ export const Emoji: FC<EmojiProps> = ({
}, [appState.currentLocale, state]);
const animate = useContext(AnimateEmojiContext);
const inversionClass = emojiToInversionClassName(code);
const fallback = showFallback ? code : null;
// If the code is invalid or we otherwise know it's not valid, show the fallback.
@@ -79,7 +87,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}}'

View File

@@ -105,12 +105,14 @@ const hotkeyMatcherMap = {
reply: just('r'),
favourite: just('f'),
boost: just('b'),
bookmark: just('d'),
quote: just('q'),
mention: just('m'),
open: any('enter', 'o'),
openProfile: just('p'),
moveDown: just('j'),
moveUp: just('k'),
moveToTop: just('0'),
toggleHidden: just('x'),
toggleSensitive: just('h'),
toggleComposeSpoilers: optionPlus('x'),
@@ -180,25 +182,24 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
if (shouldHandleEvent) {
const matchCandidates: {
handler: (event: KeyboardEvent) => void;
// A candidate will be have an undefined handler if it's matched,
// but handled in a parent component rather than this one.
handler: ((event: KeyboardEvent) => void) | undefined;
priority: number;
}[] = [];
(Object.keys(hotkeyMatcherMap) as HotkeyName[]).forEach(
(handlerName) => {
const handler = handlersRef.current[handlerName];
const hotkeyMatcher = hotkeyMatcherMap[handlerName];
if (handler) {
const hotkeyMatcher = hotkeyMatcherMap[handlerName];
const { isMatch, priority } = hotkeyMatcher(
event,
bufferedKeys.current,
);
const { isMatch, priority } = hotkeyMatcher(
event,
bufferedKeys.current,
);
if (isMatch) {
matchCandidates.push({ handler, priority });
}
if (isMatch) {
matchCandidates.push({ handler, priority });
}
},
);

View File

@@ -27,7 +27,6 @@ export const HoverCardController: React.FC = () => {
const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout();
const [setEnterTimeout, cancelEnterTimeout, delayEnterTimeout] = useTimeout();
const [setScrollTimeout] = useTimeout();
const location = useLocation();
const handleClose = useCallback(() => {
cancelEnterTimeout();
@@ -36,9 +35,12 @@ export const HoverCardController: React.FC = () => {
setAnchor(null);
}, [cancelEnterTimeout, cancelLeaveTimeout, setOpen, setAnchor]);
useEffect(() => {
const location = useLocation();
const [previousLocation, setPreviousLocation] = useState(location);
if (location !== previousLocation) {
setPreviousLocation(location);
handleClose();
}, [handleClose, location]);
}
useEffect(() => {
let isScrolling = false;

View File

@@ -1,7 +1,9 @@
import { useState, useEffect, useCallback, forwardRef } from 'react';
import { useCallback, forwardRef } from 'react';
import classNames from 'classnames';
import { usePrevious } from '../hooks/usePrevious';
import { AnimatedNumber } from './animated_number';
import type { IconProp } from './icon';
import { Icon } from './icon';
@@ -59,23 +61,6 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(
},
buttonRef,
) => {
const [activate, setActivate] = useState(false);
const [deactivate, setDeactivate] = useState(false);
useEffect(() => {
if (!animate) {
return;
}
if (activate && !active) {
setActivate(false);
setDeactivate(true);
} else if (!activate && active) {
setActivate(true);
setDeactivate(false);
}
}, [setActivate, setDeactivate, animate, active, activate]);
const handleClick: React.MouseEventHandler<HTMLButtonElement> = useCallback(
(e) => {
e.preventDefault();
@@ -112,12 +97,15 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(
...(active ? activeStyle : {}),
};
const previousActive = usePrevious(active) ?? active;
const shouldAnimate = animate && active !== previousActive;
const classes = classNames(className, 'icon-button', {
active,
disabled,
inverted,
activate,
deactivate,
activate: shouldAnimate && active,
deactivate: shouldAnimate && !active,
overlayed: overlay,
'icon-button--with-counter': typeof counter !== 'undefined',
});

View File

@@ -23,6 +23,7 @@ export const LearnMoreLink: React.FC<{ children: React.ReactNode }> = ({
onClick={handleClick}
aria-expanded={open}
aria-controls={accessibilityId}
type='button'
>
<FormattedMessage
id='learn_more_link.learn_more'
@@ -48,7 +49,11 @@ export const LearnMoreLink: React.FC<{ children: React.ReactNode }> = ({
<div className='learn-more__popout__content'>{children}</div>
<div>
<button className='link-button' onClick={handleClick}>
<button
className='link-button'
onClick={handleClick}
type='button'
>
<FormattedMessage
id='learn_more_link.got_it'
defaultMessage='Got it'

View File

@@ -32,6 +32,7 @@ export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
onClick={handleClick}
aria-label={intl.formatMessage(messages.load_more)}
title={intl.formatMessage(messages.load_more)}
type='button'
>
{loading ? (
<LoadingIndicator />

View File

@@ -7,7 +7,7 @@ interface Props {
export const LoadPending: React.FC<Props> = ({ onClick, count }) => {
return (
<button className='load-more load-gap' onClick={onClick}>
<button className='load-more load-gap' onClick={onClick} type='button'>
<FormattedMessage
id='load_pending'
defaultMessage='{count, plural, one {# new item} other {# new items}}'

View File

@@ -1,3 +1,5 @@
import classNames from 'classnames';
import logo from '@/images/logo.svg';
export const WordmarkLogo: React.FC = () => (
@@ -7,8 +9,12 @@ export const WordmarkLogo: React.FC = () => (
</svg>
);
export const IconLogo: React.FC = () => (
<svg viewBox='0 0 79 79' className='logo logo--icon' role='img'>
export const IconLogo: React.FC<{ className?: string }> = ({ className }) => (
<svg
viewBox='0 0 79 79'
className={classNames('logo logo--icon', className)}
role='img'
>
<title>Mastodon</title>
<use xlinkHref='#logo-symbol-icon' />
</svg>

View File

@@ -251,15 +251,13 @@ class MediaGallery extends PureComponent {
window.removeEventListener('resize', this.handleResize);
}
UNSAFE_componentWillReceiveProps (nextProps) {
if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
} else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
this.setState({ visible: nextProps.visible });
componentDidUpdate (prevProps) {
if (!is(prevProps.media, this.props.media) && this.props.visible === undefined) {
this.setState({ visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all' });
} else if (!is(prevProps.visible, this.props.visible) && this.props.visible !== undefined) {
this.setState({ visible: this.props.visible });
}
}
componentDidUpdate () {
if (this.node) {
this.handleResize();
}

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