Adds support to typing `---`, `___` or `***` to create a horizontal
rule.
Converting when typing `---` is actually written here as an en-dash +
`-`, because the typographer replacements extension turns `--` into an
en-dash first.
`___` and `***` are only triggered after a whitespace, because they
could also mean bold+italic.
These specs are causing far more flakes and trouble than they are worth,
I think it's just the killer
combination of relying on messagebus and background jobs along with the
specs being quite big. Let's just get rid of them...
A new user joining a community via DiscourseHub and logging in via oauth
goes through this process. This would break down for two reasons.
Reason 1: in some cases, especially on Safari mobile, the redirect in
the omniauth callback was happening too early. A new user may not be
signed in yet by that point, which means the redirect to
`/user-api-key/new` triggers a redirect to `/login` which ends up in a
bit of an infinite loop. Not all browsers exhibited this behaviour, but
Safari definitely did.
Reason 2: `/user-api-key/new` is gated via group membership using the
`user_api_key_allowed_groups` site setting. By default that is set to
include `trust_level_0`, however, auto group assignment wasn't taking
place for all user `create` events (only some that go through staged
users).
Continues the work done on
https://github.com/discourse/discourse/pull/30815.
Adds a `onebox` and an `onebox_inline` node spec, their serializers, and
a plugin that automatically converts links to oneboxes.
This might not reduce the failures to zero but some screenshots of the
failures clearly show we were still on the success message page.
Same fix than: https://github.com/discourse/discourse/pull/31750
I suspect that sometimes the button was still not disabled yet when we
where checking for it. Checking for saved confirmation should be more
resilient.
- Remove `wait: 0` and base flow on site setting instead
- Ensure full-page-login has actually opened before running `go_back` -
otherwise we'll end up going back to `about:blank`
Continues the work done on
https://github.com/discourse/discourse/pull/30815.
Extends the ProseMirror-markdown `code-block` node by integrating our
existing HighlightJS pipeline for code highlighting and adding a node
view with a `<select>` to change the language of the block.
We're also adding the markdown paste extension, which handles converting
pasted text/plain to rich content if it contains Markdown.
---------
Co-authored-by: Martin Brennan <martin@discourse.org>
Redesigned page to update site logos. `AdminBrandingLogoFormComponent`
is attached to the old logos page and the new branding page. In the next
steps, branding will replace the logos page.
A new `AdminConfigAreaCardSection` component was added hidden and less
frequently used settings.
An image placeholder was also needed because many additional logos have
a fallback to the site logo.
Finally, `twitter_summary_large_image` was renamed to
`x_summary_large_image`.
Desktop

Mobile

This commit moves most of emoji logic into the discourse-emojis gem:
https://github.com/discourse/discourse-emojis/
Most notably:
- images are now symlinked from the gem
- the gem provides path to the json files
Search aliases have also been made asynchronous and memoized. When you
will search for an emoji we will now load the aliases and store the list
for future use.
---------
Co-authored-by: David Taylor <david@taylorhq.com>
Followup e26a1175d7c33746bddbc858ad89e68cc14beefe
Adds extra functionality and tests for the admin search modal.
* Show third level plugin config pages in search, e.g. AI Usage
* Remember last used search filters
* Allow navigating search results with keyboard, using tab or up/down
and enter to go to result
* Add a placeholder beneath search input to tell the admin what to do
* Add a full page search at `/admin/search` which can be reached from
pressing Enter on the search input
* Add specs for modal and full page search
* Change admin sidebar filter "no results found" to point to full page
search
* Add keyboard shortcut help to modal for admin search
Adds a search field to the page header on desktop that is controlled by
a site setting (within Search).
The search field toggles back to the search icon (magnifying class) when
the header is minimized (ie. scrolling in topics) and restores to the
field again when header is no longer minimized.
On mobile the search experience is still the same.
Previously, the only way to author js/hbs via the admin panel was to use
`<script>` tags. This strategy is not pretty, and doesn't provide access
to proper ES module imports or gjs `<template>` syntax.
Our recommendation for most themes is still that they should be authored
using a proper IDE, the `discourse_theme` CLI, and version-controlled
using git. However, we understand that this isn't a good fit for
everyone, and that there's still a place for simple
admin-panel-ui-authored themes.
This commit introduces a "JS" tab in the admin theme editor, which
corresponds to a file named
`discourse/api-initializers/theme-initializer.gjs` in the theme. This
means that everyone will be able to move towards the more modern
syntaxes, and away from the old `<script>` patterns.
This feature allows admins to find what they are
looking for in the admin interface via a search modal.
This replaces the admin sidebar filter
as the focus of the Ctrl+/ command, but the sidebar
filter can also still be used. Perhaps at some point
we may remove it or change the shortcut.
The search modal presents the following data for filtering:
* A list of all admin pages, the same as the sidebar,
except also showing "third level" pages like
"Email > Skipped"
* All site settings
* Themes
* Components
* Reports
Admins can also filter which types of items are shown in the modal,
for example hiding Settings if they know they are looking for a Page.
In this PR, I also have the following fixes:
* Site setting filters now clear when moving between
filtered site setting pages, previously it was super
sticky from Ember
* Many translations were moved around, instead of being
in various namespaces for the sidebar links and the admin
page titles and descriptions, now everything is under
`admin.config` namespace, this makes it way easier to reuse
this text for pages, search, and sidebar, and if you change it
in one place then it is changed everywhere.
---------
Co-authored-by: Ella <ella.estigoy@gmail.com>
This change adds a new `type_source` field to the `Reviewable` model, indicating whether the Reviewable type was registered by `core`, a plugin, or an `unknown` source.
When a plugin that registered a Reviewable type is disabled, this allows us to tell the user which plugin they need to re-enable to handle any orphan reviewable items.
This commit allows admins to filter the list of feature
feed items on the "What's new?" page to _only_ show experiments.
This is useful to both find existing experiments they may have
enabled, and to get a better overview of new ones they would
like to try.
This will eventually not be required when we build a dedicated
config page for experiments.
This fixes the destination of the auth process in the following
scenarios:
- when landing on a PM or a topic as an anonymous user and then loggin
in
- when landing on a public topic, hitting Reply or Like and then logging
in
This is covered by the two specs above it:
"automatically redirects when going to /signup" and "automatically
redirects when skipping the signup form"
(Plus, it doesn't do what it says on the label.)
Currently when using the shortcuts to delete a post the UI would show
you the confirmation modal even if you don't have the right to do it.
This commit fixes the issue at the root in the
`deletePostWithConfirmation` function.
This was intended to provide a better UX for interactive elements in the
composer preview. However, the morphing strategy has irreconcilable
conflicts with our `decorateCooked` API, and so we have been unable to
enable this by default.
Going forward, we're focussing efforts on the WYSIWYG composer to
provide this kind of smooth UX, so we're dropping the
`enable_diffhtml_preview` approach.
This feature was originally experimental. We made it baseline in #29572, however this was met with some pushback, so we have decided to make it experimental again.
The original PR couldn't be reverted, but this one basically does the same by cherry-picking all the changes back.
[Security
patch](5558e72f22)
(for this [CVE](https://nvd.nist.gov/vuln/detail/CVE-2024-54133)) from
rails actionpack was backported from [Rails
8.0.0.1](https://github.com/rails/rails/blob/v8.0.1/actionpack/CHANGELOG.md#rails-8001-december-10-2024)
to previous stable versions including `7-1-stable` / `7-2-stable`.
Any previous version of Discourse upgrading to v3.4.0.beta3 and above
would have observed their sites crashing if they had invalid sources in
their CSP directive extensions.
This fix removes such invalid sources during our build of the CSP, and
logs these at a warning level so devs are able to find out why their CSP
sources were filtered out of the extendable directives.
6fd577d97d3923cec3d2458f45ebd2704703fd22 widened the scope of
`use_email_for_username_and_name_suggestions` (default false) to include
invites, which means that it fell back to a generic username like
`user1`.
This commit makes it bail out earlier in this situation, so that no
suggestion is attempted.
In a previous PR, I introduced this system spec that checks that a sidebar link is auto-generated for certain plugins.
This causes problems, because the core test suite can be run with plugins either enabled or disabled, causing flaky tests.
This commit makes the
[color-scheme-toggle](https://github.com/discourse/discourse-color-scheme-toggle)
theme component a core feature with improvements and bug fixes. The
theme component will be updated to become a no-op if the core feature is
enabled.
Noteworthy changes:
* the color mode selector has a new "Auto" option that makes the site
render in the same color mode as the user's system preference
* the splash screen respects the color mode selected by the user
* dark/light variants of category logos and background images are now
picked correctly based on the selected color mode
* a new `interface_color_selector` site setting to disable the selector
or choose its location between the sidebar footer or header
Internal topic: t/139465.
---------
Co-authored-by: Ella <ella.estigoy@gmail.com>
This commit fixes a bug in the "Dark Mode" checkbox in the interface user
preferences where the checkbox state doesn't appear in the disabled
state if the user disables dark mode.
This happens because when rendering the checkbox, we check the relevant
user options field within the controller's `init` method, but at that
point in the controller's life cycle, the `user_option` object isn't
available. What we should do instead is move this check to the route's
`setupController` method where the `user_option` object is available and
we can set the correct state on the controller.
https://meta.discourse.org/t/-/349976 (private topic)
This setting was introduced a year ago for
51016e56dd99a9ad4bd82cdc6c0cf968754c70ed, which was
formerly a design experiment.
In practice on our hosting, noone has ever disabled this
setting, and it's for a useful feature. There is no
point keeping it.

This change includes the following updates:
- Rename view all to view all drafts
- Remove view all link from drop-down when all drafts are displayed in
the menu
- Different icon for draft topics and PMs (adds envelope for PMs)
- Disable drop-down when New Topic button is disabled (private
categories etc)
- Improve drafts drop-down loading (no longer disables the trigger btn
on click)
Plugins like for example AI or Akismet create reviewable items. When the
plugin is disabled, then we cannot properly handle those items.
In that situation, we should display warnings about unhandled types.
Instruct admin to reenable plugins. In addition, we should allow the
admin to delete all pending reviews from disabled plugins.
This is the first in a series of PRs to introduce a
ProseMirror-based
WYSIWYM editor experience
alongside our current textarea Markdown editor.
Behind a hidden site setting, this PR adds a toggle to the composer
toolbar, allowing users to switch between the two options.
Our implementation builds upon the excellent ProseMirror and its
non-core Markdown
module, using the
module's schema, parsing, and serialization definitions as the base for
further Discourse-specific features.
An extension API is included to enable further customizations.
The necessary extensions to support all Discourse's core and core
plugins features **will be implemented in subsequent PRs**.
---------
Co-authored-by: David Taylor <david@taylorhq.com>
In core, `escapeExpression` was being applied during the model loading phase. However, plugin consumers of the UserStreamItem component were not necessarily doing the same.
This commit moves the emoji-replacement logic (which also safely handles escaping) into the component template, so that it is safe-by-default, regardless of how it's used by plugins.
While introducing the new drafts dropdown menu component, we also made
some changes to how the sidebar link works for Drafts. However, after
following user feedback and internal discussions we decided to revert
back to the shared link approach that combines My Posts and My Drafts.
This change adds a sidebar link for each plugin that fulfils the following criteria:
- Does not have an explicit admin route defined in the plugin.
- Has at least one site setting (not including enabled/disabled.)
That sidebar link leads to the automatically generated plugin show settings page.
This moves the "hide my public profile" checkbox from the
/my/preferences/interface > other section into the top of the
/my/preferences/profile section.
Internal ref - t/146570
Changing a tag name and reverting it to a previous tag name choice on
the same screen (meaning, without reloading the page) causes a 404
error.
Reproduction steps:
* Open an existing tag page https://your-discourse.com/tag/a
* Click the wrench, change the name and save
* Open edit again, revert the name to the original tag name
* 404 error
This was happening because of the way we find existing objects
in our store. Tags are using the name as the id/primary key
unlike other records in the UI. When we get the existing object
from the store we throw away the "new" ID, so we ended up with
the old tag ID on the existing object, which led to a 404. To
fix it we can just manually set the tag ID to what it is supposed
to be from params in the tag show route.
c.f.
https://meta.discourse.org/t/404-error-when-you-revert-a-tag-name-after-changing-it-without-reloading-the-page/342559