This PR introduces a heading/paragraph dropdown menu for the
composer toolbar, that works for both the new rich text editor, and
the old markdown editor.
Features include:
* Dynamically changing the icon based on the heading level
* Checking the current heading level in the dropdown list
* Applying the same heading level to multiple selections
---------
Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Renato Atilio <renatoat@gmail.com>
This adds some new icon aliases so the lock icon can be overridden in
specific scenarios without applying globally to all locks:
* "topic.closed"
* "topic.opened"
* "category.restricted"
This enables customizations like:

```
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer((api) => {
api.replaceIcon("topic.closed", "xmark");
api.replaceIcon("category.restricted", "shield-halved");
});
```
More documentation on this feature in
https://meta.discourse.org/t/change-icons-globally/87751
We want to add the ability to enable/disable users selecting Gravatar for their avatar.
This change adds a site setting to enable/disable the option (default to enabled.) This will prevent users from configuring Gravatars from that point on. It does not affect already configured avatars.
We're also taking this chance to hide some of the advanced settings from the UI.
The reasons for these changes is https://meta.discourse.org/t/-/89605
broke and admins were not able to log back in if they had previously
enabled the "read only" mode.
Thus ensued a deep dive into how all the "read only" modes worked, which
was made difficult due to the lack of tests.
The "cornerstone" of this PR is the `read_only_mixin.rb` file which was
improved to be able to differentiate between the "readonly" mode and the
"staff writes only" mode.
I then made use of the `allow_in_readonly_mode` and
`allow_in_staff_writes_only_mode` method to **explicitely** list all the
actions that should work in those modes.
I also added the "readonly" mixin to the `WebhooksController` since it
doesn't inherit from the `ApplicationController`.
I improved the security of the `/u/admin-login` endpoint by always
sending the same message no matter if we found or not an admin account
with the provided email address.
I added two system specs:
1. for ensuring that admins can log in via /u/admin-lgoin and then
clicking the link in the email they received while the site is in
readonly mode.
2. for ensuring the "staff writes only mode" is _actually_ tested by
ensuring a moderator can log in and create a topic while the site is in
that mode.
Plenty of specs were updated to ensure 100% converage of the various
"read only" modes.
## 🔍 Overview
This update handles how editing post translations should work. It
ensures that when you are viewing a translated post, and try to edit a
post, you are shown a dialog to either edit the original or the
translation.
## 📸 Screenshots
<img width="843" alt="Screenshot 2025-06-24 at 14 49 53"
src="https://github.com/user-attachments/assets/fce82b2f-8c48-4f3b-ae0a-46a6afbf742e"
/>
This commit fixes a problem in the new reviewable item template that
uses the `reviewable-refresh/topic-link` component where a topic is
always shown as deleted even if the topic is present.
Adds a `` input rule that uses the markdown parser to
create an image node.
Supporting this format surfaced an issue with dimension-less images, so
now the image node view uses the max width/height site settings in
addition to the loaded image natural dimensions to determine what a 100%
looks like – it's used for display, and also when a zoom-out button
action is taken, so we calculate the next step % of the calculated
dimensions.
This commit addresses an issue where the removal of users/groups was targeting the wrong user.
---------
Co-authored-by: Sérgio Saquetim <saquetim@discourse.org>
This is mostly a fix for the UI which incorrectly disables the badge
grouping field for system badges. However, nothing in the backend
suggests that the badge grouping for system badges is disallowed. This
is confirmed by the fact that `Badge.protected_system_fields` do not
list the `badge_grouping_id` column as protected.
Fixes an issue where a URL like this:
```
https://meta.discourse.org/admin/site_settings/category/all_results?filter=discourse connect
```
Would appear to be broken when inserting into the composer via the
hyperlink modal. All we have to do is escape it before inserting,
and unescape before editing it in the modal.
Also in this commit I am renaming the InsertHyperlink modal to
UpsertHyperlink,
since it is used for both inserting and editing links.
This change makes it easier to edit typos when adding mentions to
composer's rich text mode. Previously we would keep invalid mentions as
mention nodes and use a data attribute to identify if they were valid or
not and style them based on that. This would mean that pressing
backspace would delete the entire mention and you would have to type
again from scratch.
The updated approach is to replace the invalid mention node with text
and in turn removes the need to use the data attribute to identify
valid/invalid mentions.
Displays a toolbar and the alt text of the image when it's selected.
The toolbar allows changing the scale between 50, 75 and 100 and
deleting the image.
The alt text display can be clicked/focused to open an editable input.
https://github.com/user-attachments/assets/330f5c7c-e29a-46ab-b2cd-e7c7c07c15bf
It also introduces a simple GlimmerNodeView class that serves as a
bridge between ProseMirror NodeViews and Glimmer components, which is
used on this new version of the image node.
---------
Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
* Fixes capitalisation for *My messages*, *My posts*, and *My drafts*
sidebar links.
* Hides *My messages* link for anonymous users.
* Hides *My messages* link for users who can’t access messages.
* Adds active state for *My messages* link (applies to all child routes:
personal, group, and tags).
In the follow cases:
- no text selection
- invalid text selection (outside of the cooked of a post)
The quote state should be cleared. This commit also adds a spec to
prevent similar regressions.
Prior to this change, off topic and something else flags did not have
the right CSS classes set resulting in the right colors not being set
for the badges used to display the flag reasons.
This commit also updates the colors used for the off topic and illegal
flags to reflect the severity. Before this change, the badge color for
illegal was green while the badge color for off topic is blue. Those
colors are too "positive".
### Screenshots
#### Before
<img width="718" alt="Screenshot 2025-07-03 at 3 22 49 PM"
src="https://github.com/user-attachments/assets/cc10d078-fe58-41aa-8c15-4bba86eb90e5"
/>
#### After
<img width="715" alt="Screenshot 2025-07-03 at 3 23 02 PM"
src="https://github.com/user-attachments/assets/e039e042-68ae-4e76-bd5a-62116ef020a3"
/>
This commit adds a `use_reviewable_ui_refresh` attribute to the
`CurrentUserSerializer` and updates the client side to use this
attribute as a feature flag to determine when the new reviewable UI
should be shown.
The current colour palette editor has a ‘Copy to clipboard’ button on it
that copies a JSON object of the current palette’s colours. This commit
adds the button to the new colour palette UI.
This PR improves the user invite list for both desktop and mobile views:
* Simplified table layout
* Better layout on mobile
* Removes extra padding and header row clutter
* Better alignment of columns and row spacing
* Keeps invite details compact but clear
* Improved group display
* Group icons and names are now properly aligned side-by-side
* Consistent inline styling for multiple groups per invite
* Updated row actions
* Moves the Remove action into a dropdown to reduce accidental clicks and keep destructive actions less prominent
* Uses consistent button styling (Edit and More actions)
This commit replaces the `toolbar-popup-menu-options`, which used
`select-kit` with a new implementation using `dmenu`.
---------
Co-authored-by: Renato Atilio <renato@discourse.org>
Co-authored-by: Martin Brennan <martin@discourse.org>
This commit adds a header with badges indicating why a reviewable was
created in the refreshed reviewable UI that is currently being hidden
behind the `reviewable_ui_refresh` site setting.
Co-authored-by: Gary <gary@pento.net>
`ReviewableClaimedTopic` has an `onClaim` arg, which is used by the calling components to locally mutate the value of `reviewable.claimed_by`.
This was being incorrectly mutated to a `User` model, when it needs to match the `ReviewableClaimedTopicSerializer` output.
List of small changes for the system Horizon theme:
- Remove"Created by: system"
- Remove All Extra Files section
- Move translation to core
- Remove settings editor button
- Remove export button
Dropdown and multiselect components lack `InputTip`, which makes them
not show any reason when validation fails.
This commit also adds a new i18n message for select fields, after this
commit, if a multiselect or dropdown custom field required has no option
selected, it will display a `Please select a value for "XX" field`
validation error when the Signup button is clicked.
**Problem**
An error is showing up for staff members when trying to upload images
and `SiteSetting.authorized_extensions = ""` and
`SiteSetting.authorized_extensions_for_staff != ""` because
`this.currentUser` is not defined in the `UppyUploader` component
This commit introduces an experimental `reviewable_ui_refresh` site
setting of `group_list` type. When a user is part of any group
configured in the site setting, the new reviewable UI will be shown to
the user.
Co-authored-by: Gary <gary@pento.net>
Adds support of an optional subheader to the core welcome banner.
Similarly to header it accepts `logged in` and `anonymous` copies.
---------
Co-authored-by: Martin Brennan <martin@discourse.org>
We want to add a hidden limit to the number of locales an admin can set
for localization. This is a safe limit to prevent excessive localization
(if each post can be localized to 10 locales, that's 10x the amount of
storage and tokens needed).
t/157677
When a modal is opened as part of a reviewable action, we automatically mark a reviewable as claimed, so that other site staff won't accidentally start working on that reviewable. If the modal is cancelled out of, however, we weren't removing the claimed flag.
The parent component of `ThemeSettingRelativesSelectorComponent`,
`SiteSettingComponent`, has recently been migrated from being a legacy
component to a Glimmer component (in
https://github.com/discourse/discourse/pull/33255), but we missed
updating the child class to use Glimmer's patterns, namely how arguments
are accessed in Glimmer components (`this.args.foo` vs `this.foo`).
Previously, there was no way to edit post localizations, so the
`post.raw` was always returning the localized value. With localization
UI and endpoints now, we want to always return the original raw and the
composer to reflect the original value.
https://github.com/discourse/discourse/pull/33184 will handle the
decision to show the post edit composer or the post localization
composer.
Followup fb7fa2902cf685ee9d4002e5448b4817f2dbef98,
prevent opening the chat channel selector with Ctrl/Meta+K
in any inputs except the chat composer, most of the time you
do not want this, but especially in the topic composer.
In that case, you want the link insert modal to open.
This PR introduces explicit state management for decorators as part of
the quote controls refactor. The legacy quote controls logic has been
migrated to a new Glimmer component, and state handling for decorator
functions associated with post content rendering is now formalized and
standardized.
### Key Points
- **Decorator State Introduction:**
- Introduces explicit state objects for use within post and cooked-html
decorators, replacing previous ad-hoc or implicit state tracking.
- Uses `TrackedMap` for state management, improving reactivity and
ensuring consistent, predictable updates when decorator state changes.
- **Component Refactor:**
- The quote controls logic is now fully encapsulated in a Glimmer
component, leveraging the new decorator state handling for cleaner, more
maintainable code.
- Legacy implementations have been removed to reduce technical debt.
- **Context and Data Handling:**
- Decorators and components now receive state and context as explicit
parameters, standardizing the interface and improving code readability.
- Direct properties (such as `post`, `highlightTerm`, and
`ignoredUsers`) replace the previous `data` object, simplifying context
management.
- **Other Improvements:**
- Enhanced error handling for async content.
- Improved extensibility by supporting custom wrapper elements in quoted
content.
- Added functionality to highlight original quoted text.
---------
Co-authored-by: David Taylor <david@taylorhq.com>
This PR relates to the locale setting in the composer and fixes 2
quirks:
- When replying to a post, the composer sets the locale of the new post
in composer to the locale of the post being replied. This PR defaults
the value to "none"
- When creating a new post, the composer sets the locale to the user's
locale. However we are seeing the behaviour that users do not write in
the locale they set their profile to. This PR defaults the value to
"none"
This adds a link for each authentication providers that are listed in
/my/preferences/account in the "Associated Accounts" section.
This is particularly useful when Discourse is being used in the PWA or
in the DiscourseMobile app where there's no browser bar available and
the only way to visit the provider's website is to open a browser
window.
That way, they can _just_ click the provider's name.
Internal ref - t/156255
---
**BEFORE**

**AFTER**

This PR takes the localization features out of "experimental" to prep
for the announcement
- rename settings and gives them its own area
- `experimental_content_localization` to `content_localization_enabled`
- `experimental_content_localization_allowed_groups` to
`content_localization_allowed_groups`
- `experimental_content_localization_supported_locales` to
`content_localization_supported_locales`
- `experimental_anon_language_switcher` to
`content_localization_anon_language_switcher`
- migration
- related to https://github.com/discourse/discourse-ai/pull/1439
| screenshot 📸 |
|---|
| <img width="964" alt="Screenshot 2025-06-17 at 5 06 32 PM"
src="https://github.com/user-attachments/assets/9a8b2c38-c846-4fc9-8ddd-815c45cc3d0e"
/> |
Adds a Discourse ID authenticator. Not available for use in production
just yet, but soon communities will be able to use this service to let
users authenticate using a central Discourse ID account.
Includes a support for a `/revoke` action, allowing users to log out of
multiple client instances from a central auth service.
Internal ticket: t/155397
---------
Co-authored-by: Loïc Guitaut <loic@discourse.org>
Strips the site's base URL and `https`/`mailto` protocols from the link
toolbar display

Refactors the toolbar to use getters instead of function calls, re-uses
`DButton` for the `href` toolbar item instead of a custom `a` tag, fixes
a bug where we passed a translated string to DButton's `label` that
expects a i18n key, and adds support to “disabled” buttons.
Slightly simplifies the toolbar implementation by extracting one step of
indirection removing `toolbarButton` from d-editor.