We just added this site setting to be used for switchover as we merge a theme component into core. However, as it wasn't marked client: true, the theme component cannot read it. 🤦
When Translation Overrides are changed, a message is sent on the
`/i18n-flush` channel to ensure all running unicorns flush their caches.
This message is not received in a database-specific context, so running
`ExtraLocalesController.clear_cache!` was only affecting the default
site in a multisite cluster. This commit updates it to flush caches for
all sites.
## 🔍 Overview
This update adds the ability for users to manually add translations to
specific posts. It adds a 🌐 icon on the post menu where you can click to
add translations for posts.
It also introduces a new site setting:
`content_localization_debug_allowed_groups` which is convenient when
debugging localized posts. It adds a globe icon in the post meta data
area along with a number of how many languages the post is translated
in. Hovering over the icon will show a tooltip with access to editing
and deleting the translated posts.
## 📸 Screenshots
<img width="1234" alt="Screenshot 2025-05-07 at 13 26 09"
src="https://github.com/user-attachments/assets/9d65374d-ee3e-4e8b-b171-b98db6f90f23"
/>
<img width="300" alt="Screenshot 2025-05-07 at 13 26 41"
src="https://github.com/user-attachments/assets/6ee9c5e6-16ed-4dab-97ec-9401804a4ac8"
/>
This commit makes various changes and improvements to the new color palettes
page that was introduced in
https://github.com/discourse/discourse/pull/32379. Specifically, it:
* Removes the ‘Logos and fonts’ banner
* Removes the icon from the palette names in the list
* Moves the ‘new’ button to the top of the palette list
* Excludes theme-owned color palettes from the color palettes page since
these will be editable directly from the theme page
* Makes the name the primary text if a color has no description
* Adds a button next to the name field to save just the name
* Adds a ‘Delete’ button alongside the existing ‘Duplicate’ button
* Adds a ‘Revert’ button to change a modified color back to its default
value (based on the base palette of the palette)
Follow-up to https://github.com/discourse/discourse/pull/31742
This commit adds a color palettes list to the new color palette edit page
that was introduced in the linked PR to allow navigating between color
palettes. It reuses the same UI that we already have in the legacy color
palette UI (`/admin/customize/colors`), but we may redesign the page in
the future.
There are instances of posts being deleted by system_user where the context is left blank in the staff action logs, leading to confusion about why exactly they have been deleted.
This change deprecates using the PostDestroyer as system_user without providing a context, and adds a context to all call sites currently missing it in core. Plugins to be done after this is merged.
In this PR we hide search input.
https://github.com/discourse/discourse/pull/32485
However, search input is much more intuitive. Therefore, input was
brought back and opens modal on click. In addition, search link was
removed.
In https://github.com/discourse/discourse/pull/31375, the
glimmer_post_stream_mode_auto_groups setting was added. While
translating, I noticed its description is identical to the one for
glimmer_topic_list_mode - both say "post menu implementation". I assume
this was actually meant to refer to the "post stream" instead? Since
glimmer_post_stream_mode uses "post stream implementation", I expected
this setting - also related to the post stream - to follow the same
wording.
I had also mentioned this on Crowdin about two weeks ago, but didn’t get
a reply.
We are no longer using any of the transpilation/bundling features of
Sprockets. We only use it to serve assets in development, and then
collect & fingerprint them in production. This commit switches us to use
the more modern "Propshaft" gem for that functionality.
Propshaft is much simpler than Sprockets. Instead of taking a
combination of paths + "precompile" list, Propshaft simply assumes all
files in the configured directory are required in production. Previously
we had some base paths configured quite high in the directory structure,
and then only precompiled selected assets within the directory. That's
no longer possible, so this commit refactors those places (mostly
plugin-related) to use dedicated directories under
`app/assets/generated/`.
Another difference is that Propshaft applies asset digests in
development as well as production. This is great for caching & dev/prod
consistency, but does mean some small changes were required in tests.
We previously had some freedom-patches applied to Sprockets. Some of
those had to be ported across to Propshaft. We now have three patches:
1. Skip adding digest hashes to webpack-generated chunks (which are
already digested, and referred to from other js files)
2. Avoid raising errors for missing assets in test mode. We don't always
compile assets before running basic RSpec tests.
3. Maintain relative paths for sourcemap URLs, so that files don't need
to be recompiled depending on their CDN path
Significant refactors are made to the `assets.rake` and `s3.rake` tasks,
which rely on implementation details of Sprockets/Propshaft.
We are making this the only option for our login/signup
pages on April 29th, 2025, per
https://meta.discourse.org/t/introducing-our-new-fullscreen-signup-and-login-pages/340401.
This commit removes the `full_page_login` setting and any logic
around it, as well as deleting the old login and signup modals,
and removing leftover problem checks and settings from the database.
This JS was used to wrap long usernames. Nowadays in core, we use a
simpler `word-break: break-all;` pattern, so it makes sense to use the
same simplification in the embedded comments view.
Previously all locale bundles would be built & compressed during
assets:precompile. For most sites, only one of these languages was
actually used, so this is fairly wasteful.
This commit moves the main locale bundle into the
ExtraLocalesController, which has recently undergone many improvements
to make it more efficient. This allows locale files to be bundled "just
in time" when they're first accessed.
Now that brotli level=6 is enabled for these assets in our nginx config,
this change should have no impact on the locale bundle size.
This commit adds
- `topic_localization` containing its topic, a locale, title, and
fancy_title
- `post_localization` containing its post, a locale, raw, cooked, the
associated post's version
- and also APIs to add them
Reviewer note: We may ask ourselves "why create separate models instead
of one that is generic?" but the different localizable models may be
vastly different. For example in posts we only have raw that we need to
translate, and topics we have only title, but for categories we have
name and description. Then, we may ask ourselves "why not create a
polymorphic one that takes in model and column name?" and then we end up
with the same thing as what we have currently which is custom fields
(which is a mess in itself). Also, when replacing the untranslated
content to the translated one, we may find it easier to just `join` +
`coalesce` on the dedicated table - it would be a much simpler query
than polymorphism.
This will show the experimental rich_editor setting and admins
can turn it on for their site. It is still marked experimental
because there are some features missing, but it works well for
95% of cases.
---------
Co-authored-by: Renato Atilio <renato@discourse.org>
This enables on-the-fly brotli compression at level 4 for all responses
which we currently gzip. This level should provide slightly improved
file sizes when compared to gzip, as well as slightly faster processing
times. This is the [level which Cloudflare
use](https://blog.cloudflare.com/results-experimenting-brotli/) for
dynamic responses.
When compared to our existing gzip level-5 configuration, our own
experiments confirm that it provides slightly faster compression, with
slightly smaller file sizes.
For static assets which are cached by CDNs/browsers, we use brotli level
6 for an even better compression ratio.
At the moment the reply count is labelled by the topic list's header
column, which is good — but we don't actually describe what the link
does, so it's a little ambiguous.
This adds an aria-label to describe the behavior "jump to first post" so
it will be read as:
"n replies, jump to first post"
This provides better coverage for link-to-link navigation because it
both describes the number and the function.
Over the past couple of weeks we've been adding Settings tabs to a lot of admin sections, to categorize some of the previously uncategorized site settings.
Now that all that is done, we can remove the Advanced > Other section, which used to contain them.
Previously, clicking "Groups" on the admin dashboard would bring you to the public groups page. Historically, the public and admin actions have been mixed together on that page.
This is a bit of a frustrating experience when working on the admin dashboard, and also prevented us from adding a "Settings" tab for group-related site settings.
This PR adds an "admin groups" page, which is just an exact copy of the public groups index for now. This allows us to add the "Settings" tab, and lets us gradually work un disentangling the public- and admin parts of groups.
This change does two things:
Modernizes the admin badges UI implementation. (Routes + controllers → components + services.)
Adds a Settings tab to the new badges page.
For all intents and purposes, this change is a lift-and-shift modernization. The addition of the settings tab is trivial once that is covered.
Adds support for a tag-chooser in form templates. It supports single tag
and multi tags. The source of the displayed tags has to be a tag_group
name.
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
This commit adds a `:sidekiq_job_error` event which is
triggered when an error is encountered while running a Sidekiq job. The
intent of this change is to complement the `:sidekq_job_ran` event which
can be used with the `:sidekiq_job_error` event to calculate the error
rate for each job.
Allow admins to edit user custom flags. Because changing
name/description will update name/description for old reviewables,
warning has to be displayed.
Still, system flags can never be edited or deleted (only disabled).
This is already included in nginx's default set, and is currently
causing this message to be printed:
> nginx: [warn] duplicate extension "wasm", content type:
"application/wasm", previous content type: "application/wasm" in
/etc/nginx/conf.d/discourse.conf:4
This commits changes the language for components that aren't used on any themes to be "used/unused" instead of "active/inactive" throughout the new components listing page.
The `DMultiSelect` component provides a customizable multi-select
dropdown with support for both mouse and keyboard interactions.

### Parameters
#### `@loadFn` (required)
An async function that returns the data to populate the dropdown
options.
```javascript
const loadFn = async () => {
return [
{ id: 1, name: "Option 1" },
{ id: 2, name: "Option 2" },
];
};
```
#### `@compareFn`
A function used to determine equality between items. This is
particularly useful when working with complex objects. By default, `id`
will be used.
```javascript
const compareFn = (a, b) => {
return a.name === b.name;
};
```
#### `@selection`
An array of pre-selected items that will be displayed as selected when
the component renders.
```javascript
const selection = [
{ id: 1, name: "Option 1" },
{ id: 2, name: "Option 2" },
];
```
#### `@label`
Text label displayed in the trigger element when no items are selected.
```javascript
@label="Select options"
```
### Named Blocks
#### :selection
Block for customizing how selected items appear in the trigger.
```javascript
<:selection as |result|>{{result.name}}</:selection>
```
#### :result
Block for customizing how items appear in the dropdown list.
```javascript
<:result as |result|>{{result.name}}</:result>
```
#### :result
Block for customizing how errors appear in the component.
```javascript
<:error as |error|>{{error}}</:error>
```
### Example Usage
```javascript
<DMultiSelect
@loadFn={{this.loadOptions}}
@selection={{this.selectedItems}}
@compareFn={{this.compareItems}}
@label="Select options">
<:selection as |result|>{{result.name}}</:selection>
<:result as |result|>{{result.name}}</:result>
<:error as |error|>{{error}}</:error>
</DMultiSelect>
```
Co-Authored-By: Jordan Vidrine
<30537603+jordanvidrine@users.noreply.github.com>
---------
Co-authored-by: Jordan Vidrine <30537603+jordanvidrine@users.noreply.github.com>
This makes two tweaks to the setup wizard:
1. Move the branding (site logo) step to after styling (look & feel).
2. Remove the corporate (your organization) step.
This commit removes the Ctrl+F search shortcut, which hijacks the
browser search shortcut in Discourse. We are doing this because there
has been many years of complaints around this behaviour, and now that
we have the new header search it has become even more annoying.
We originally added this because we lazy load posts in a topic, and it
might not have been immediately clear to users that they are not
searching
all the posts in the topic when pressing Ctrl+F. However, that was 10+
years
ago, most people are very familiar with lazy loading now, it doesn't
make sense
to keep this additional hijack for this one topic use case.
Search is still accessible by pressing the `/` shortcut.