Some themes make use of the category background color even when using
emojis or icons as the category style.
Therefore we should always allow the color selector to be visible when
editing the category.
Currently when using `register_topic_preloader_associations`, we are
not able to specify a condition that is evaluated at runtime.
This commit allows specifying a condition and also keeps backward
compatibility.
```
register_topic_preloader_associations(:linked_topic) { true }
register_topic_preloader_associations({
first_post: [uploads]
})
```
When bulk removing tags, the tag topic count isn't updated. You have to wait for the daily "ensure consistency" job to run for it to update properly. This is causing downstream problems, like the inability to use the "remove unused tags" feature.
The counter updating is handled on destroy by the join table model TopicTag. But we are calling #delete_all to perform the bulk tag removal, which bypasses callbacks.
This changes from #delete_all to #destroy_all, which invokes callbacks and updates the counters.
- adds .d-editor-container--rich-editor-enabled to d-editor-container
- conditionally swaps textarea to monospace when
siteSettings.rich_editor is enabled
We are doing this intentionally on the old composer when the
new rich editor is enabled to further differentiate the two and
to make it clear that markdown is the "source code"
This is a follow up to 59edec46a3de105e720bd2c716ae34d636794044
Test is flaky and seems to require more time to complete on CI so we
double the max wait time for now to see if it reduces the test's
flakiness.
SASS deprecation warnings are quite noisy, especially when
running specs, here is an example:
```
Deprecation Warning [mixed-decls]: Sass's behavior for declarations that appear after nested
rules will be changing to match the behavior specified by CSS in an upcoming
version. To keep the existing behavior, move the declaration above the nested
rule. To opt into the new behavior, wrap the declaration in `& {}`.
More info: https://sass-lang.com/d/mixed-decls
╷
52 │ ┌ @media screen and (max-width: 1048px) {
53 │ │ right: 0;
54 │ │ }
│ └─── nested rule
... │
56 │ background: var(--secondary);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ declaration
╵
theme-entrypoint/desktop.scss 56:5 @import
/home/mb/repos/discourse/desktop.scss 3:9 root stylesheet
Deprecation Warning [mixed-decls]: Sass's behavior for declarations that appear after nested
rules will be changing to match the behavior specified by CSS in an upcoming
version. To keep the existing behavior, move the declaration above the nested
rule. To opt into the new behavior, wrap the declaration in `& {}`.
```
This commit adds an env var (`QUIET_SASS_DEPRECATIONS`) to control
turning them off.
On 1st April 2025, we start showing no icons if the icon name used is a
deprecated one and therefore no longer part of the svg set.
We'll continue showing the messages with the correct icon name to aid
correction of these names.
Console logging will now be done at an error level for such icons.
We retain the behaviour of raising an error for such icons in plugins
from svg_sprite.rb in test environments, but removed this from
icon-library.js as it's harder to test the actual expected behaviour of
returning the original icon now that it's not part of the deprecation
workflow. (sinon.stub doesn't work well here for `isTesting` - the
alternative would be to override the environment.js module with
`proxyquire`) In any case, once we remove the mapping logic, we won't be
raising errors in test environment either for this scenario.
In a development environment, the server auto-restarter can't watch symlinked paths, which means that any symlinked plugins won't reload if their non-autoloaded files change.
This change does a simple resolve of the symlink for any symlinked plugins, and adds the real plugin path to those that it will auto-restart for.
These aren't technically needed in the output, since we inline all
styles. However, there's no harm in including them, and having them
visible will improve the developer experience when restyling emails.
iOS is automatically converting a double-hyphen (--) to an em-dash (–).
It may get in the way when we're trying to create an horizontal rule
with a ---, so this PR adds the "em-dash + hyphen" case to our input
rule regex.
This commit also ensures meta will resize with the textarea to avoid
meta being badly positioned.
I couldn't easily write a test working on all platforms.
Currently when using `register_topic_preloader_associations`, we are not
able to specify a condition that is evaluated at runtime.
This commit allows specifying a condition and also keeps backward
compatibility.
```
register_topic_preloader_associations({
association: :linked_topic, condition: ->(topic) { topic.custom_field.present? }
})
```
Before this fix a click on a d-menu trigger would fire a click on the
parent element, which could have undesired consequences.
This also fixes two things:
- moves float-kit/form-kit css files higher in the chain, so it's easier
to override
- increases the z-index of the notifications-tracking menu content or it
would be behind the timeline control
This property is used for the `isNew` and `isCreated` computed
properties, which are then used in templates. To make that work
correctly, we need to use `.set` or `@tracked`.
This change removes the foreground color category setting to simplify
the category creation and edit process for admins.
Instead we determine the highest contrasting color (either white or
black) based on the background color.
Contrast algorithm is based on:
https://www.w3.org/TR/AERT/#color-contrast
We also implement the value transformer as part of this change, which
allows overriding the category text color.
This commit allows the ProseMirror rich editor to display chat
transcripts copied from chat using the "Copy" button.
The BBCode usually looks something like this:
```
[chat quote="hunter;29856;2025-03-20T07:13:04Z" channel="design gems 🎉" channelId="95"]
haha **ok** _cool_
[/chat]
```
But there are several variations that must be accounted for:
* Single message from single user
* Multiple messages from a single and multiple users
* Messages inside chat threads
The rich transcript extension has to ignore many of the chat transcript
markdown
tokens because they simply aren't necessary -- none of the ProseMirror
nodes need
to be editable. So, we basically recreate the same HTML that the chat
transcript markdown
rule does in the `toDOM()` function. Maybe in future we want to make the
markdown rule
do less and have this HTML creation in one place, but for now we need to
mirror in both files.
---------
Co-authored-by: Renato Atilio <renato@discourse.org>
When a site has the `must_approve_users` setting enabled, new user data is stored on the Reviewable model, including username, email, and any other data that is entered during signup. If the user is rejected, that data is retained, without a clear path to deleting it.
In order to allow data that could be PII to be removed, without breaking Discourse's audit and logging trails, this change scrubs the PII from the relevant `ReviewableUser` and `UserHistory` objects, replacing that data with who scrubbed it, and why.
When passing our ProsemirrorEditor component an initial value,
we were sometimes passing `null`, which causes the error in
the title of this commit. The fix here is to handle `null`
gracefully as string.
We originally found this on the category edit page, since
we have a `<DEditor />` in the form template form for the
category.
7d587937 introduced css property deduplication in emails to workaround
bugs in some email clients. However, this didn't account for
admin-supplied customizations which were overriding core rules using
`!important`. This commit ensures that the deduplicator will always
prioritise `!important` rules, just like a browser.
The rules are:
- between 1 and 3 emojis: bigger emoji
- more than 3 or any text or node in the same paragraph: regular emoji
This is implemented through a prose mirror plugin, which try to be smart
and recompute only edited paragraphs. Full scan on first load.
---------
Co-authored-by: Renato Atilio <renato@discourse.org>
This is a hidden site setting which has never been publicized, and is
not recommended for use. If we decide to add a feature like this in
future as a visible site setting, it would need many more safeguards to
prevent misuse.
The `using_wait_time` DSL did not work when used in the `around` context
as the Capybara's session has not been initialized.
Follow-up to afde7cc1727a751e4d87be2ceee17f2d82edf89c
I'm not sure what is causing the tests to be flaky so I need more
information to determine where the problem is. For now, I'm doubling the
wait time to rule out any server side problem.
We are not waiting for asynchronous operations to complete before
executing our assertions.
### Reviewer notes
Example test failure:
https://github.com/discourse/discourse/actions/runs/14100970402/job/39496976787
```
Failure/Error: measurement = Benchmark.measure { example.run }
expected `Chat::Channel.count` to have changed by 1, but was changed by 0
[Screenshot Image]: /__w/discourse/discourse/tmp/capybara/failures_r_spec_example_groups_chat_new_message_from_params_with_multiple_users_creates_a_dm_channel_when_none_exists_626.png
~~~~~~~ JS LOGS ~~~~~~~
~~~~~ END JS LOGS ~~~~~
./plugins/chat/spec/system/chat_new_message_spec.rb:57:in `block (3 levels) in <main>'
./spec/rails_helper.rb:619:in `block (3 levels) in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/benchmark-0.4.0/lib/benchmark.rb:304:in `measure'
./spec/rails_helper.rb:619:in `block (2 levels) in <top (required)>'
./spec/rails_helper.rb:580:in `block (3 levels) in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/timeout-0.4.3/lib/timeout.rb:185:in `block in timeout'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/timeout-0.4.3/lib/timeout.rb:192:in `timeout'
./spec/rails_helper.rb:570:in `block (2 levels) in <top (required)>'
./spec/rails_helper.rb:527:in `block (2 levels) in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/webmock-3.25.1/lib/webmock/rspec.rb:39:in `block (2 levels) in <top (required)>'
```
Some site settings support backfilling if the user specified it. This works fine for singular site settings sent to the SiteSettingsController#update endpoint, but with bulk save we need to support this for a list of settings as well.
This change alters the params format for SiteSetting::Update.
It also moves the backfill logic into the service.
A system test in `system/search_spec.rb` was failing with the following
error frequently on CI:
```
Failure/Error: expect(search_page).to have_heading_text("Search")
expected `#<PageObjects::Pages::Search:0x00007fb9fcd3f028>.has_heading_text?("Search")` to be truthy, got false
[Screenshot Image]: /__w/discourse/discourse/tmp/capybara/failures_r_spec_example_groups_search_when_using_full_page_search_on_mobile_works_and_clears_search_page_state_912.png
~~~~~~~ JS LOGS ~~~~~~~
(no logs)
~~~~~ END JS LOGS ~~~~~
./spec/system/search_spec.rb:42:in `block (3 levels) in <main>'
./spec/rails_helper.rb:619:in `block (3 levels) in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/benchmark-0.4.0/lib/benchmark.rb:304:in `measure'
./spec/rails_helper.rb:619:in `block (2 levels) in <top (required)>'
./spec/rails_helper.rb:580:in `block (3 levels) in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/timeout-0.4.3/lib/timeout.rb:185:in `block in timeout'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/timeout-0.4.3/lib/timeout.rb:192:in `timeout'
./spec/rails_helper.rb:570:in `block (2 levels) in <top (required)>'
./spec/rails_helper.rb:527:in `block (2 levels) in <top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/webmock-3.25.1/lib/webmock/rspec.rb:39:in `block (2 levels) in <top (required)>'
```
The failure screenshot shows that the "user" is on the homepage even
though we have already clicked the search icon and ensured that the user
can see the search container. I suspect there is some sort of race
condition here since Capybara executes clicks in quick sucession where
we clicked on both the homepage logo and the search icon. It may be
possible that Ember redirected the user to the search page first
before the browser was able to finish navigating the user to the `/`
href.
### Reviewer notes
Test flaked in
https://github.com/discourse/discourse/actions/runs/14085443789/job/39448197089
with the following failure screenshot:

This is to provide diagnostic information for some flaky system tests
which we are currently investigating. The previous attempt in
6f92f42eb83fea61b2712aaaefcc124e4939365d only dumped threads that
contains the `puma` gem in the backtrace but that is not enough. Since I
am now printing all thread backtraces, I added the
`dump_threads_on_failure` metadata
which will be used to determine if all the thread backtraces should be
printed out in the spec's failure output.